diff options
Diffstat (limited to 'lib/tools')
83 files changed, 6055 insertions, 6804 deletions
diff --git a/lib/tools/Makefile b/lib/tools/Makefile index 685f3398e9..e17e9cfd1e 100644 --- a/lib/tools/Makefile +++ b/lib/tools/Makefile @@ -1,18 +1,19 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2009. All Rights Reserved. +# Copyright Ericsson AB 1996-2016. All Rights Reserved. # -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. +# 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. # # %CopyrightEnd% # @@ -23,7 +24,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk # Macros # ---------------------------------------------------- -SUB_DIRECTORIES = c_src src doc/src examples priv emacs +SUB_DIRECTORIES = c_src src doc/src examples emacs include vsn.mk VSN = $(TOOLS_VSN) diff --git a/lib/tools/c_src/Makefile.in b/lib/tools/c_src/Makefile.in index b1eb69f9dc..cfe91917f8 100644 --- a/lib/tools/c_src/Makefile.in +++ b/lib/tools/c_src/Makefile.in @@ -1,18 +1,19 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2009-2012. All Rights Reserved. +# Copyright Ericsson AB 2009-2016. All Rights Reserved. # -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. +# 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 # -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. +# 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. # # %CopyrightEnd% # @@ -96,11 +97,8 @@ DRIVERS= ifneq ($(strip $(ETHR_LIB_NAME)),) # Need ethread package for emem -ifneq ($(findstring ose,$(TARGET)),ose) -# Do not build on OSE PROGS += $(BIN_DIR)/emem$(TYPEMARKER)@EXEEXT@ endif -endif EMEM_OBJ_DIR=$(OBJ_DIR)/emem CREATE_DIRS += $(EMEM_OBJ_DIR) @@ -151,12 +149,7 @@ ERTS_LIB = $(ERL_TOP/erts/lib_src/obj/$(TARGET)/$(TYPE)/MADE _create_dirs := $(shell mkdir -p $(CREATE_DIRS)) -ifneq ($(findstring ose,$(TARGET)),ose) all: $(PROGS) $(DRIVERS) -else -# Do not build dynamic files on OSE -all: -endif $(ERTS_LIB): $(make_verbose)cd $(ERL_TOP)/erts/lib_src && $(MAKE) $(TYPE) diff --git a/lib/tools/c_src/erl_memory.c b/lib/tools/c_src/erl_memory.c index c4e126a7b1..13a3fccc6d 100644 --- a/lib/tools/c_src/erl_memory.c +++ b/lib/tools/c_src/erl_memory.c @@ -1,18 +1,19 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2003-2013. All Rights Reserved. + * Copyright Ericsson AB 2003-2016. All Rights Reserved. * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. + * 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 * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. + * 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. * * %CopyrightEnd% */ diff --git a/lib/tools/c_src/erl_memory_trace_block_table.c b/lib/tools/c_src/erl_memory_trace_block_table.c index 9c19358f14..ca7cb45a0e 100644 --- a/lib/tools/c_src/erl_memory_trace_block_table.c +++ b/lib/tools/c_src/erl_memory_trace_block_table.c @@ -1,13 +1,14 @@ -/* ``The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved via the world wide web at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. +/* ``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. * * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings diff --git a/lib/tools/c_src/erl_memory_trace_block_table.h b/lib/tools/c_src/erl_memory_trace_block_table.h index 1b1f23c16f..ead3afc8fb 100644 --- a/lib/tools/c_src/erl_memory_trace_block_table.h +++ b/lib/tools/c_src/erl_memory_trace_block_table.h @@ -1,13 +1,14 @@ -/* ``The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved via the world wide web at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. +/* ``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. * * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings diff --git a/lib/tools/doc/src/Makefile b/lib/tools/doc/src/Makefile index e3a2d64041..d9c3b0ad2a 100644 --- a/lib/tools/doc/src/Makefile +++ b/lib/tools/doc/src/Makefile @@ -1,18 +1,19 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2012. All Rights Reserved. +# Copyright Ericsson AB 1997-2016. All Rights Reserved. # -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. +# 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 # -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. +# 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. # # %CopyrightEnd% # diff --git a/lib/tools/doc/src/book.xml b/lib/tools/doc/src/book.xml index 6260bcdf3a..38d0408156 100644 --- a/lib/tools/doc/src/book.xml +++ b/lib/tools/doc/src/book.xml @@ -4,20 +4,21 @@ <book xmlns:xi="http://www.w3.org/2001/XInclude"> <header titlestyle="normal"> <copyright> - <year>1997</year><year>2013</year> + <year>1997</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + 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. </legalnotice> diff --git a/lib/tools/doc/src/cover.xml b/lib/tools/doc/src/cover.xml index 07ffa65e3d..15cd784253 100644 --- a/lib/tools/doc/src/cover.xml +++ b/lib/tools/doc/src/cover.xml @@ -5,20 +5,21 @@ <header> <copyright> <year>2001</year> - <year>2013</year> + <year>2015</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. + 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 - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + 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. The Initial Developer of the Original Code is Ericsson AB. </legalnotice> @@ -138,17 +139,18 @@ </desc> </func> <func> - <name>compile(ModFile) -> Result</name> - <name>compile(ModFile, Options) -> Result</name> - <name>compile_module(ModFile) -> Result</name> - <name>compile_module(ModFile, Options) -> Result</name> - <fsummary>Compile a module for Cover analysis.</fsummary> + <name>compile(ModFiles) -> Result | [Result]</name> + <name>compile(ModFiles, Options) -> Result | [Result]</name> + <name>compile_module(ModFiles) -> Result | [Result]</name> + <name>compile_module(ModFiles, Options) -> Result | [Result]</name> + <fsummary>Compile one or more modules for Cover analysis.</fsummary> <type> + <v>ModFiles = ModFile | [ModFile]</v> <v>ModFile = Module | File</v> <v> Module = atom()</v> <v> File = string()</v> <v>Options = [Option]</v> - <v> Option = {i,Dir} | {d,Macro} | {d,Macro,Value}</v> + <v> Option = {i,Dir} | {d,Macro} | {d,Macro,Value} | export_all</v> <d>See <c>compile:file/2.</c></d> <v>Result = {ok,Module} | {error,File} | {error,not_main_node}</v> </type> @@ -165,6 +167,9 @@ returns <c>{ok,Module}</c>. Otherwise the function returns <c>{error,File}</c>. Errors and warnings are printed as they occur.</p> + <p>If a list of <c>ModFiles</c> is given as input, a list + of <c>Result</c> will be returned. The order of the returned + list is undefined.</p> <p>Note that the internal database is (re-)initiated during the compilation, meaning any previously collected coverage data for the module will be lost.</p> @@ -194,9 +199,10 @@ </desc> </func> <func> - <name>compile_beam(ModFile) -> Result</name> - <fsummary>Compile a module for Cover analysis, using an existing beam.</fsummary> + <name>compile_beam(ModFiles) -> Result | [Result]</name> + <fsummary>Compile one or more modules for Cover analysis, using existing beam(s).</fsummary> <type> + <v>ModFiles = ModFile | [ModFile]</v> <v>ModFile = Module | BeamFile</v> <v> Module = atom()</v> <v> BeamFile = string()</v> @@ -229,6 +235,9 @@ returned.</p> <p><c>{error,BeamFile}</c> is returned if the compiled code can not be loaded on the node.</p> + <p>If a list of <c>ModFiles</c> is given as input, a list + of <c>Result</c> will be returned. The order of the returned + list is undefined.</p> </desc> </func> <func> @@ -251,16 +260,21 @@ </desc> </func> <func> - <name>analyse(Module) -> {ok,Answer} | {error,Error}</name> - <name>analyse(Module, Analysis) -> {ok,Answer} | {error,Error}</name> - <name>analyse(Module, Level) -> {ok,Answer} | {error,Error}</name> - <name>analyse(Module, Analysis, Level) -> {ok,Answer} | {error,Error}</name> - <fsummary>Analyse a Cover compiled module.</fsummary> + <name>analyse() -> {result,Ok,Fail} | {error,not_main_node}</name> + <name>analyse(Modules) -> OneResult | {result,Ok,Fail} | {error,not_main_node}</name> + <name>analyse(Analysis) -> {result,Ok,Fail} | {error,not_main_node}</name> + <name>analyse(Level) -> {result,Ok,Fail} | {error,not_main_node}</name> + <name>analyse(Modules, Analysis) -> OneResult | {result,Ok,Fail} | {error,not_main_node}</name> + <name>analyse(Modules, Level) -> OneResult | {result,Ok,Fail} | {error,not_main_node}</name> + <name>analyse(Analysis, Level) -> {result,Ok,Fail} | {error,not_main_node}</name> + <name>analyse(Modules, Analysis, Level) -> OneResult | {result,Ok,Fail} | {error,not_main_node}</name> + <fsummary>Analyse one or more Cover compiled modules.</fsummary> <type> - <v>Module = atom()</v> + <v>Modules = Module | [Module]</v> + <v>Module = atom() </v> <v>Analysis = coverage | calls</v> <v>Level = line | clause | function | module</v> - <v>Answer = {Module,Value} | [{Item,Value}]</v> + <v>OneResult = {ok,{Module,Value}} | {ok,[{Item,Value}]} | {error, Error}</v> <v> Item = Line | Clause | Function</v> <v> Line = {M,N}</v> <v> Clause = {M,F,A,C}</v> @@ -269,49 +283,67 @@ <v> N = A = C = integer()</v> <v> Value = {Cov,NotCov} | Calls</v> <v> Cov = NotCov = Calls = integer()</v> - <v>Error = {not_cover_compiled,Module} | not_main_node</v> + <v> Error = {not_cover_compiled,Module}</v> + <v>Ok = [{Module,Value}] | [{Item,Value}]</v> + <v>Fail = [Error]</v> </type> <desc> - <p>Performs analysis of a Cover compiled module <c>Module</c>, as + <p>Performs analysis of one or more Cover compiled modules, as specified by <c>Analysis</c> and <c>Level</c> (see above), by examining the contents of the internal database.</p> <p><c>Analysis</c> defaults to <c>coverage</c> and <c>Level</c> defaults to <c>function</c>.</p> - <p>If <c>Module</c> is not Cover compiled, the function returns - <c>{error,{not_cover_compiled,Module}}</c>.</p> - <p>HINT: It is possible to issue multiple analyse_to_file commands at - the same time. </p> + <p>If <c>Modules</c> is an atom (one module), the return will + be <c>OneResult</c>, else the return will be + <c>{result,Ok,Fail}</c>.</p> + <p>If <c>Modules</c> is not given, all modules that have data + in the cover data table, are analysed. Note that this + includes both cover compiled modules and imported + modules.</p> + <p>If a given module is not Cover compiled, this is indicated + by the error reason <c>{not_cover_compiled,Module}</c>.</p> </desc> </func> <func> - <name>analyse_to_file(Module) -> </name> - <name>analyse_to_file(Module,Options) -> </name> - <name>analyse_to_file(Module, OutFile) -> </name> - <name>analyse_to_file(Module, OutFile, Options) -> {ok,OutFile} | {error,Error}</name> - <fsummary>Detailed coverage analysis of a Cover compiled module.</fsummary> + <name>analyse_to_file() -> {result,Ok,Fail} | {error,not_main_node}</name> + <name>analyse_to_file(Modules) -> Answer | {result,Ok,Fail} | {error,not_main_node}</name> + <name>analyse_to_file(Options) -> {result,Ok,Fail} | {error,not_main_node}</name> + <name>analyse_to_file(Modules,Options) -> Answer | {result,Ok,Fail} | {error,not_main_node}</name> + <fsummary>Detailed coverage analysis of one or more Cover compiled modules.</fsummary> <type> + <v>Modules = Module | [Module]</v> <v>Module = atom()</v> - <v>OutFile = string()</v> + <v>OutFile = OutDir = string()</v> <v>Options = [Option]</v> - <v>Option = html</v> - <v>Error = {not_cover_compiled,Module} | {file,File,Reason} | no_source_code_found | not_main_node</v> + <v>Option = html | {outfile,OutFile} | {outdir,OutDir}</v> + <v>Answer = {ok,OutFile} | {error,Error}</v> + <v>Ok = [OutFile]</v> + <v>Fail = [Error]</v> + <v>Error = {not_cover_compiled,Module} | {file,File,Reason} | {no_source_code_found,Module}</v> <v> File = string()</v> <v> Reason = term()</v> </type> <desc> - <p>Makes a copy <c>OutFile</c> of the source file for a module - <c>Module</c>, where it for each executable line is specified + <p>Makes copies of the source file for the given modules, + where it for each executable line is specified how many times it has been executed.</p> <p>The output file <c>OutFile</c> defaults to <c>Module.COVER.out</c>, or <c>Module.COVER.html</c> if the option <c>html</c> was used.</p> - <p>If <c>Module</c> is not Cover compiled, the function returns - <c>{error,{not_cover_compiled,Module}}</c>.</p> + <p>If <c>Modules</c> is an atom (one module), the return will + be <c>Answer</c>, else the return will be a + list, <c>{result,Ok,Fail}</c>.</p> + <p>If <c>Modules</c> is not given, all modules that have data + in the cover data table, are analysed. Note that this + includes both cover compiled modules and imported + modules.</p> + <p>If a module is not Cover compiled, this is indicated by the + error reason <c>{not_cover_compiled,Module}</c>.</p> <p>If the source file and/or the output file cannot be opened using <c>file:open/2</c>, the function returns <c>{error,{file,File,Reason}}</c> where <c>File</c> is the file name and <c>Reason</c> is the error reason.</p> - <p>If the module was cover compiled from the <c>.beam</c> + <p>If a module was cover compiled from the <c>.beam</c> file, i.e. using <c>compile_beam/1</c> or <c>compile_beam_directory/0,1</c>, it is assumed that the source code can be found in the same directory as the @@ -322,10 +354,8 @@ joining <c>../src</c> and the tail of the compiled path below a trailing <c>src</c> component, then the compiled path itself. - If no source code is found, - <c>{error,no_source_code_found}</c> is returned.</p> - <p>HINT: It is possible to issue multiple analyse_to_file commands at - the same time. </p> + If no source code is found, this is indicated by the error reason + <c>{no_source_code_found,Module}</c>.</p> </desc> </func> <func> @@ -339,7 +369,7 @@ <v>OutFile = string()</v> <v>Options = [Option]</v> <v>Option = html</v> - <v>Error = {not_cover_compiled,Module} | {file,File,Reason} | no_source_code_found | not_main_node</v> + <v>Error = {not_cover_compiled,Module} | {file,File,Reason} | {no_source_code_found,Module} | not_main_node</v> <v> File = string()</v> <v> Reason = term()</v> </type> diff --git a/lib/tools/doc/src/cover_chapter.xml b/lib/tools/doc/src/cover_chapter.xml index f29f59bee0..3847adbe59 100644 --- a/lib/tools/doc/src/cover_chapter.xml +++ b/lib/tools/doc/src/cover_chapter.xml @@ -4,20 +4,21 @@ <chapter> <header> <copyright> - <year>2001</year><year>2013</year> + <year>2001</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + 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. </legalnotice> @@ -450,48 +451,5 @@ ok <p>When Cover is stopped, all Cover compiled modules are unloaded.</p> </section> </section> - - <section> - <title>Using the Web Based User Interface to Cover</title> - - <section> - <title>Introduction</title> - <p>To ease the use of Cover there is a web based user interface - to Cover called WebCover. WebCover is designed to be started - and used via WebTool. It is possible to Cover compile Erlang - modules and to generate printable Cover and Call analyses via - the web based user interface.</p> - </section> - - <section> - <title>Start the Web Based User Interface to Cover</title> - <p>To start WebCover you can either start WebTool, point a - browser to the start page of WebTool and start WebCover from - there, or you can use the <c>start_webtool</c> script to start - Webtool, WebCover and a browser. See WebTool documentation for - further information.</p> - <p>Currently WebCover is only compatible - with Internet Explorer and Netscape Navigator 4.0 and higher.</p> - </section> - - <section> - <title>Navigating WebCover</title> - <p>From the menu in the lefthand frame you can select the - <c>Nodes</c>, <c>Compile</c>, <c>Import</c> or <c>Result</c> - page.</p> - <p>From the <c>Nodes</c> page you can add remote nodes to - participate in the coverage analysis. Coverage data from all - involved nodes will then be merged during analysis.</p> - <p>From the <c>Compile</c> page you can Cover compile <c>.erl</c> - or <c>.beam</c> files.</p> - <p>From the <c>Import</c> page you can import coverage data from - a previous analysis. Imported data will then be merged with - the current coverage data. <em>Note</em> that it is only possible to - import files with the extension <c>.coverdata</c>.</p> - <p>From the <c>Result</c> page you can analyse, reset or export - coverage data.</p> - <p>Please follow the instructions on each page.</p> - </section> - </section> </chapter> diff --git a/lib/tools/doc/src/cprof.xml b/lib/tools/doc/src/cprof.xml index 553597837e..df0acbe617 100644 --- a/lib/tools/doc/src/cprof.xml +++ b/lib/tools/doc/src/cprof.xml @@ -5,20 +5,21 @@ <header> <copyright> <year>2002</year> - <year>2013</year> + <year>2016</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. + 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 - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + 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. The Initial Developer of the Original Code is Ericsson AB. </legalnotice> @@ -66,7 +67,7 @@ <func> <name>analyse() -> {AllCallCount, ModAnalysisList}</name> <name>analyse(Limit) -> {AllCallCount, ModAnalysisList}</name> - <name>analyse(Mod) -> ModAnlysis</name> + <name>analyse(Mod) -> ModAnalysis</name> <name>analyse(Mod, Limit) -> ModAnalysis</name> <fsummary>Collect and analyse call counters.</fsummary> <type> diff --git a/lib/tools/doc/src/cprof_chapter.xml b/lib/tools/doc/src/cprof_chapter.xml index 6536d43e0f..ba1e7432fd 100644 --- a/lib/tools/doc/src/cprof_chapter.xml +++ b/lib/tools/doc/src/cprof_chapter.xml @@ -4,20 +4,21 @@ <chapter> <header> <copyright> - <year>2002</year><year>2013</year> + <year>2002</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + 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. </legalnotice> diff --git a/lib/tools/doc/src/eprof.xml b/lib/tools/doc/src/eprof.xml index 73fd563fbd..f098b7d39e 100644 --- a/lib/tools/doc/src/eprof.xml +++ b/lib/tools/doc/src/eprof.xml @@ -4,20 +4,21 @@ <erlref> <header> <copyright> - <year>1996</year><year>2013</year> + <year>1996</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. + 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 - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + 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. </legalnotice> @@ -130,13 +131,13 @@ <name>analyze() -> ok</name> <name>analyze(Type) -> ok</name> <name>analyze(Type,Options) -> ok</name> + <fsummary>Display profiling results per process.</fsummary> <type> <v>Type = procs | total</v> <v>Options = [{filter, Filter} | {sort, Sort}</v> <v>Filter = [{calls, integer()} | {time, float()}]</v> <v>Sort = time | calls | mfa</v> </type> - <fsummary>Display profiling results per process.</fsummary> <desc> <p>Call this function when profiling has been stopped to display the results per process, that is:</p> diff --git a/lib/tools/doc/src/erlang_mode.xml b/lib/tools/doc/src/erlang_mode.xml index 747c41d554..00cf5196b4 100644 --- a/lib/tools/doc/src/erlang_mode.xml +++ b/lib/tools/doc/src/erlang_mode.xml @@ -4,20 +4,21 @@ <erlref> <header> <copyright> - <year>2003</year><year>2013</year> + <year>2003</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + 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. </legalnotice> @@ -251,6 +252,7 @@ behavior</item> <item>gen_event - skeleton for the OTP gen_event behavior</item> <item>gen_fsm - skeleton for the OTP gen_fsm behavior</item> + <item>gen_statem - skeleton for the OTP gen_statem behavior</item> <item>Library module - skeleton for a module that does not implement a process.</item> <item>Corba callback - skeleton for a Corba callback module.</item> diff --git a/lib/tools/doc/src/erlang_mode_chapter.xml b/lib/tools/doc/src/erlang_mode_chapter.xml index 3be1d53ca2..b4e30d883b 100644 --- a/lib/tools/doc/src/erlang_mode_chapter.xml +++ b/lib/tools/doc/src/erlang_mode_chapter.xml @@ -4,20 +4,21 @@ <chapter> <header> <copyright> - <year>2003</year><year>2013</year> + <year>2003</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + 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. </legalnotice> diff --git a/lib/tools/doc/src/fprof.xml b/lib/tools/doc/src/fprof.xml index f83c049fcd..4c9e48045e 100644 --- a/lib/tools/doc/src/fprof.xml +++ b/lib/tools/doc/src/fprof.xml @@ -4,20 +4,21 @@ <erlref> <header> <copyright> - <year>2001</year><year>2013</year> + <year>2001</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + 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. </legalnotice> diff --git a/lib/tools/doc/src/fprof_chapter.xml b/lib/tools/doc/src/fprof_chapter.xml index 462b3f9579..5a2a5ad47c 100644 --- a/lib/tools/doc/src/fprof_chapter.xml +++ b/lib/tools/doc/src/fprof_chapter.xml @@ -4,20 +4,21 @@ <chapter> <header> <copyright> - <year>2001</year><year>2013</year> + <year>2001</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + 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. </legalnotice> diff --git a/lib/tools/doc/src/instrument.xml b/lib/tools/doc/src/instrument.xml index 3f278b63cd..bb6f9b6100 100644 --- a/lib/tools/doc/src/instrument.xml +++ b/lib/tools/doc/src/instrument.xml @@ -4,20 +4,21 @@ <erlref> <header> <copyright> - <year>1998</year><year>2013</year> + <year>1998</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + 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. </legalnotice> diff --git a/lib/tools/doc/src/lcnt.xml b/lib/tools/doc/src/lcnt.xml index 9754b107fe..9c8ce148e9 100644 --- a/lib/tools/doc/src/lcnt.xml +++ b/lib/tools/doc/src/lcnt.xml @@ -5,22 +5,23 @@ <header> <copyright> <year>2009</year> - <year>2013</year> + <year>2016</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - The Initial Developer of the Original Code is Ericsson AB. + 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. + + The Initial Developer of the Original Code is Ericsson AB. </legalnotice> <title>lcnt</title> diff --git a/lib/tools/doc/src/lcnt_chapter.xml b/lib/tools/doc/src/lcnt_chapter.xml index 1b8595749d..6cfdb5cf1b 100644 --- a/lib/tools/doc/src/lcnt_chapter.xml +++ b/lib/tools/doc/src/lcnt_chapter.xml @@ -4,20 +4,21 @@ <chapter> <header> <copyright> - <year>2009</year><year>2013</year> + <year>2009</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. + 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 - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + 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. </legalnotice> diff --git a/lib/tools/doc/src/make.xml b/lib/tools/doc/src/make.xml index f4d64fa9e2..fddf5ebd7b 100644 --- a/lib/tools/doc/src/make.xml +++ b/lib/tools/doc/src/make.xml @@ -5,20 +5,21 @@ <header> <copyright> <year>1996</year> - <year>2013</year> + <year>2016</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. + 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 - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + 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. The Initial Developer of the Original Code is Ericsson AB. </legalnotice> @@ -75,7 +76,7 @@ Load mode. Loads all recompiled modules.</item> <item><c>netload</c> <br></br> - Net load mode. Loads all recompiled modules an all known nodes.</item> + Net load mode. Loads all recompiled modules on all known nodes.</item> </list> <p>All items in <c>Options</c> that are not make options are assumed to be compiler options and are passed as-is to diff --git a/lib/tools/doc/src/notes.xml b/lib/tools/doc/src/notes.xml index 38b57b73a9..3a6ac37eef 100644 --- a/lib/tools/doc/src/notes.xml +++ b/lib/tools/doc/src/notes.xml @@ -4,20 +4,21 @@ <chapter> <header> <copyright> - <year>2004</year><year>2013</year> + <year>2004</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + 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. </legalnotice> @@ -30,6 +31,134 @@ </header> <p>This document describes the changes made to the Tools application.</p> +<section><title>Tools 2.8.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + <c>cover:compile_beam/1</c> and + <c>cover:compile_beam_directory/1,2</c> crashed when + trying to compile a beam file without a <c>'file'</c> + attribute. This has been corrected and an error is + returned instead.</p> + <p> + Thanks to Louis-Philippe Gauthier for reporting this bug.</p> + <p> + Own Id: OTP-13200</p> + </item> + <item> + <p>Fix a bit string comprehension bug in Cover. </p> + <p> + Own Id: OTP-13277 Aux Id: PR 856 </p> + </item> + </list> + </section> + +</section> + +<section><title>Tools 2.8.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The emacs mode does not add a newline after the arrow on + -callback lines anymore.</p> + <p> + Own Id: OTP-13042</p> + </item> + </list> + </section> + +</section> + +<section><title>Tools 2.8.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + If a module includes eunit.hrl, a parse transform adds + the function test/0 on line 0 in the module. A bug in + OTP-18.0 caused cover:analyse_to_file/1 to fail to insert + cover data in the output file when line 0 existed in the + cover data table. This is now corrected.</p> + <p> + Own Id: OTP-12981</p> + </item> + </list> + </section> + +</section> + +<section><title>Tools 2.8</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + In order to improve performance of the cover tool, new + functions are added for cover compilation and analysis on + multiple files. This allows for more parallelisation.</p> + <p> + Some improvements of the data base access is also done in + order to improve the performance when analysing and + resetting cover data.</p> + <p> + Minor incompatibility: An error reason from + analyse_to_file is changed from no_source_code_found to + {no_source_code_found,Module}.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-12330 Aux Id: seq12757 </p> + </item> + <item> + <p>Attempting to do a <c>cover</c> analysis when neither + source code nor beam file could be found would hang the + <c>cover</c> server. Corrected to return a proper + error.</p> + <p> + Own Id: OTP-12806</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Allow maps for supervisor flags and child specs</p> + <p> + Earlier, supervisor flags and child specs were given as + tuples. While this is kept for backwards compatibility, + it is now also allowed to give these parameters as maps, + see <seealso + marker="stdlib:supervisor#sup_flags">sup_flags</seealso> + and <seealso + marker="stdlib:supervisor#child_spec">child_spec</seealso>.</p> + <p> + Own Id: OTP-11043</p> + </item> + <item> + <p> + Remove Mnemosyne rules support.</p> + <p> + Own Id: OTP-12511</p> + </item> + <item> + <p> + Add printout of total number of calls and time in eprof</p> + <p> + Own Id: OTP-12681</p> + </item> + </list> + </section> + +</section> + <section><title>Tools 2.7.2</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/tools/doc/src/notes_history.xml b/lib/tools/doc/src/notes_history.xml index 2058dd8fde..d955cbde69 100644 --- a/lib/tools/doc/src/notes_history.xml +++ b/lib/tools/doc/src/notes_history.xml @@ -4,20 +4,21 @@ <chapter> <header> <copyright> - <year>2006</year><year>2013</year> + <year>2006</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + 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. </legalnotice> diff --git a/lib/tools/doc/src/part.xml b/lib/tools/doc/src/part.xml index 5b03e1db55..796047fe8d 100644 --- a/lib/tools/doc/src/part.xml +++ b/lib/tools/doc/src/part.xml @@ -4,20 +4,21 @@ <part xmlns:xi="http://www.w3.org/2001/XInclude"> <header> <copyright> - <year>1996</year><year>2013</year> + <year>1996</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. + 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 - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + 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. </legalnotice> diff --git a/lib/tools/doc/src/part_notes.xml b/lib/tools/doc/src/part_notes.xml index 3527d5e3d9..c4c6fa4d7d 100644 --- a/lib/tools/doc/src/part_notes.xml +++ b/lib/tools/doc/src/part_notes.xml @@ -4,20 +4,21 @@ <part xmlns:xi="http://www.w3.org/2001/XInclude"> <header> <copyright> - <year>2004</year><year>2013</year> + <year>2004</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + 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. </legalnotice> diff --git a/lib/tools/doc/src/part_notes_history.xml b/lib/tools/doc/src/part_notes_history.xml index 43c0abd05a..a34e35fc56 100644 --- a/lib/tools/doc/src/part_notes_history.xml +++ b/lib/tools/doc/src/part_notes_history.xml @@ -5,20 +5,21 @@ <header> <copyright> <year>2006</year> - <year>2013</year> + <year>2016</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. + 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 - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + 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. The Initial Developer of the Original Code is Ericsson AB. </legalnotice> diff --git a/lib/tools/doc/src/ref_man.xml b/lib/tools/doc/src/ref_man.xml index 7b68e18a75..d2131e7a93 100644 --- a/lib/tools/doc/src/ref_man.xml +++ b/lib/tools/doc/src/ref_man.xml @@ -4,20 +4,21 @@ <application xmlns:xi="http://www.w3.org/2001/XInclude"> <header> <copyright> - <year>1996</year><year>2013</year> + <year>1996</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. + 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 - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + 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. </legalnotice> diff --git a/lib/tools/doc/src/tags.xml b/lib/tools/doc/src/tags.xml index 0aa0ca8e35..ea0ae5cc4d 100644 --- a/lib/tools/doc/src/tags.xml +++ b/lib/tools/doc/src/tags.xml @@ -5,20 +5,21 @@ <header> <copyright> <year>1998</year> - <year>2013</year> + <year>2016</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. + 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 - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + 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. The Initial Developer of the Original Code is Ericsson AB. </legalnotice> diff --git a/lib/tools/doc/src/xref.xml b/lib/tools/doc/src/xref.xml index da16efa005..8c49f3a206 100644 --- a/lib/tools/doc/src/xref.xml +++ b/lib/tools/doc/src/xref.xml @@ -4,20 +4,21 @@ <erlref> <header> <copyright> - <year>2000</year><year>2013</year> + <year>2000</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. + 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 - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + 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. </legalnotice> diff --git a/lib/tools/doc/src/xref_chapter.xml b/lib/tools/doc/src/xref_chapter.xml index db9f774186..8b14e03064 100644 --- a/lib/tools/doc/src/xref_chapter.xml +++ b/lib/tools/doc/src/xref_chapter.xml @@ -4,20 +4,21 @@ <chapter> <header> <copyright> - <year>2000</year><year>2013</year> + <year>2000</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + 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. </legalnotice> diff --git a/lib/tools/emacs/Makefile b/lib/tools/emacs/Makefile index 69946be24a..585425e5f1 100644 --- a/lib/tools/emacs/Makefile +++ b/lib/tools/emacs/Makefile @@ -1,13 +1,14 @@ -# ``The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved via the world wide web at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. +# ``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. # # The Initial Developer of the Original Code is Ericsson Utvecklings AB. # Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings diff --git a/lib/tools/emacs/erlang-eunit.el b/lib/tools/emacs/erlang-eunit.el index 0adeff1a02..3b85e6680a 100644 --- a/lib/tools/emacs/erlang-eunit.el +++ b/lib/tools/emacs/erlang-eunit.el @@ -1,18 +1,19 @@ ;; ;; %CopyrightBegin% ;; -;; Copyright Ericsson AB 2009-2010. All Rights Reserved. +;; Copyright Ericsson AB 2009-2016. All Rights Reserved. ;; -;; The contents of this file are subject to the Erlang Public License, -;; Version 1.1, (the "License"); you may not use this file except in -;; compliance with the License. You should have received a copy of the -;; Erlang Public License along with this software. If not, it can be -;; retrieved online at http://www.erlang.org/. +;; 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 ;; -;; Software distributed under the License is distributed on an "AS IS" -;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -;; the License for the specific language governing rights and limitations -;; under the License. +;; 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. ;; ;; %CopyrightEnd% ;;; diff --git a/lib/tools/emacs/erlang-skels-old.el b/lib/tools/emacs/erlang-skels-old.el index b88d7bcc4b..4087bc3013 100644 --- a/lib/tools/emacs/erlang-skels-old.el +++ b/lib/tools/emacs/erlang-skels-old.el @@ -1,18 +1,19 @@ ;; ;; %CopyrightBegin% ;; -;; Copyright Ericsson AB 2010. All Rights Reserved. +;; Copyright Ericsson AB 2010-2016. All Rights Reserved. ;; -;; The contents of this file are subject to the Erlang Public License, -;; Version 1.1, (the "License"); you may not use this file except in -;; compliance with the License. You should have received a copy of the -;; Erlang Public License along with this software. If not, it can be -;; retrieved online at http://www.erlang.org/. +;; 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 ;; -;; Software distributed under the License is distributed on an "AS IS" -;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -;; the License for the specific language governing rights and limitations -;; under the License. +;; 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. ;; ;; %CopyrightEnd% ;;; @@ -815,7 +816,7 @@ Please see the function `tempo-define-template'.") "%% Note: This directive should only be used in test suites." n "-compile(export_all)." n n - "-include_lib(\"test_server/include/test_server.hrl\")." n n + "-include_lib(\"common_test/include/ct.hrl\")." n n (erlang-skel-separator 2) "%% TEST SERVER CALLBACK FUNCTIONS" n @@ -838,7 +839,7 @@ Please see the function `tempo-define-template'.") "Config." n n (erlang-skel-separator 2) - "%% Function: end_per_suite(Config) -> void()" n + "%% Function: end_per_suite(Config) -> term()" n "%%" n "%% Config = [tuple()]" n "%% A list of key/value pairs, holding the test case configuration." n @@ -867,7 +868,7 @@ Please see the function `tempo-define-template'.") "Config." n n (erlang-skel-separator 2) - "%% Function: end_per_testcase(TestCase, Config) -> void()" n + "%% Function: end_per_testcase(TestCase, Config) -> term()" n "%%" n "%% TestCase = atom()" n "%% Name of the test case that is finished." n @@ -993,7 +994,7 @@ Please see the function `tempo-define-template'.") "Config." n n (erlang-skel-separator 2) - "%% Function: end_per_suite(Config0) -> void() | {save_config,Config1}" n + "%% Function: end_per_suite(Config0) -> term() | {save_config,Config1}" n "%%" n "%% Config0 = Config1 = [tuple()]" n "%% A list of key/value pairs, holding the test case configuration." n @@ -1021,7 +1022,7 @@ Please see the function `tempo-define-template'.") (erlang-skel-separator 2) "%% Function: end_per_group(GroupName, Config0) ->" n - "%% void() | {save_config,Config1}" n + "%% term() | {save_config,Config1}" n "%%" n "%% GroupName = atom()" n "%% Name of the test case group that is finished." n @@ -1054,7 +1055,7 @@ Please see the function `tempo-define-template'.") (erlang-skel-separator 2) "%% Function: end_per_testcase(TestCase, Config0) ->" n - "%% void() | {save_config,Config1} | {fail,Reason}" n + "%% term() | {save_config,Config1} | {fail,Reason}" n "%%" n "%% TestCase = atom()" n "%% Name of the test case that is finished." n @@ -1175,7 +1176,7 @@ Please see the function `tempo-define-template'.") "Config." n n (erlang-skel-separator 2) - "%% Function: end_per_suite(Config0) -> void() | {save_config,Config1}" n + "%% Function: end_per_suite(Config0) -> term() | {save_config,Config1}" n "%% Config0 = Config1 = [tuple()]" n (erlang-skel-separator 2) "end_per_suite(_Config) ->" n > @@ -1193,7 +1194,7 @@ Please see the function `tempo-define-template'.") (erlang-skel-separator 2) "%% Function: end_per_group(GroupName, Config0) ->" n - "%% void() | {save_config,Config1}" n + "%% term() | {save_config,Config1}" n "%% GroupName = atom()" n "%% Config0 = Config1 = [tuple()]" n (erlang-skel-separator 2) @@ -1212,7 +1213,7 @@ Please see the function `tempo-define-template'.") (erlang-skel-separator 2) "%% Function: end_per_testcase(TestCase, Config0) ->" n - "%% void() | {save_config,Config1} | {fail,Reason}" n + "%% term() | {save_config,Config1} | {fail,Reason}" n "%% TestCase = atom()" n "%% Config0 = Config1 = [tuple()]" n "%% Reason = term()" n diff --git a/lib/tools/emacs/erlang-skels.el b/lib/tools/emacs/erlang-skels.el index 78929ac510..ce26c83295 100644 --- a/lib/tools/emacs/erlang-skels.el +++ b/lib/tools/emacs/erlang-skels.el @@ -1,18 +1,19 @@ ;; ;; %CopyrightBegin% ;; -;; Copyright Ericsson AB 2010. All Rights Reserved. +;; Copyright Ericsson AB 2010-2016. All Rights Reserved. ;; -;; The contents of this file are subject to the Erlang Public License, -;; Version 1.1, (the "License"); you may not use this file except in -;; compliance with the License. You should have received a copy of the -;; Erlang Public License along with this software. If not, it can be -;; retrieved online at http://www.erlang.org/. +;; 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 ;; -;; Software distributed under the License is distributed on an "AS IS" -;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -;; the License for the specific language governing rights and limitations -;; under the License. +;; 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. ;; ;; %CopyrightEnd% ;;; @@ -55,6 +56,8 @@ erlang-skel-gen-event erlang-skel-header) ("gen_fsm" "gen-fsm" erlang-skel-gen-fsm erlang-skel-header) + ("gen_statem" "gen-statem" + erlang-skel-gen-statem erlang-skel-header) ("wx_object" "wx-object" erlang-skel-wx-object erlang-skel-header) ("Library module" "gen-lib" @@ -352,26 +355,25 @@ Please see the function `tempo-define-template'.") "%% @doc" n "%% Whenever a supervisor is started using supervisor:start_link/[2,3]," n "%% this function is called by the new process to find out about" n - "%% restart strategy, maximum restart frequency and child" n + "%% restart strategy, maximum restart intensity, and child" n "%% specifications." n "%%" n "%% @spec init(Args) -> {ok, {SupFlags, [ChildSpec]}} |" n "%% ignore |" n "%% {error, Reason}" n (erlang-skel-separator-end 2) - "init([]) ->" n> - "RestartStrategy = one_for_one," n> - "MaxRestarts = 1000," n> - "MaxSecondsBetweenRestarts = 3600," n + "init([]) ->" n "" n> - "SupFlags = {RestartStrategy, MaxRestarts, MaxSecondsBetweenRestarts}," n + "SupFlags = #{strategy => one_for_one," n> + "intensity => 1," n> + "period => 5}," n "" n> - "Restart = permanent," n> - "Shutdown = 2000," n> - "Type = worker," n - "" n> - "AChild = {'AName', {'AModule', start_link, []}," n> - "Restart, Shutdown, Type, ['AModule']}," n + "AChild = #{id => 'AName'," n> + "start => {'AModule', start_link, []}," n> + "restart => permanent," n> + "shutdown => 5000," n> + "type => worker," n> + "modules => ['AModule']}," n "" n> "{ok, {SupFlags, [AChild]}}." n n @@ -379,7 +381,7 @@ Please see the function `tempo-define-template'.") "%%% Internal functions" n (erlang-skel-double-separator-end 3) ) - "*The template of an supervisor behaviour. + "*The template of a supervisor behaviour. Please see the function `tempo-define-template'.") (defvar erlang-skel-supervisor-bridge @@ -449,7 +451,7 @@ Please see the function `tempo-define-template'.") "%%% Internal functions" n (erlang-skel-double-separator-end 3) ) - "*The template of an supervisor_bridge behaviour. + "*The template of a supervisor_bridge behaviour. Please see the function `tempo-define-template'.") (defvar erlang-skel-generic-server @@ -858,6 +860,122 @@ Please see the function `tempo-define-template'.") "*The template of a gen_fsm. Please see the function `tempo-define-template'.") +(defvar erlang-skel-gen-statem + '((erlang-skel-include erlang-skel-large-header) + "-behaviour(gen_statem)." n n + + "%% API" n + "-export([start_link/0])." n + n + "%% gen_statem callbacks" n + "-export([init/1, terminate/3, code_change/4])." n + "-export([state_name/3])." n + "-export([handle_event/4])." n + n + "-define(SERVER, ?MODULE)." n + n + "-record(data, {})." n + n + (erlang-skel-double-separator-start 3) + "%%% API" n + (erlang-skel-double-separator-end 3) n + (erlang-skel-separator-start 2) + "%% @doc" n + "%% Creates a gen_statem process which calls Module:init/1 to" n + "%% initialize. To ensure a synchronized start-up procedure, this" n + "%% function does not return until Module:init/1 has returned." n + "%%" n + (erlang-skel-separator-end 2) + "-spec start_link() ->" n> + "{ok, Pid :: pid()} |" n> + "ignore |" n> + "{error, Error :: term()}." n + "start_link() ->" n> + "gen_statem:start_link({local, ?SERVER}, ?MODULE, [], [])." n + n + (erlang-skel-double-separator-start 3) + "%%% gen_statem callbacks" n + (erlang-skel-double-separator-end 3) n + (erlang-skel-separator-start 2) + "%% @private" n + "%% @doc" n + "%% Whenever a gen_statem is started using gen_statem:start/[3,4] or" n + "%% gen_statem:start_link/[3,4], this function is called by the new" n + "%% process to initialize." n + (erlang-skel-separator-end 2) + "-spec init(Args :: term()) -> " n> + "{gen_statem:callback_mode()," n> + "State :: term(), Data :: term()} |" n> + "{gen_statem:callback_mode()," n> + "State :: term(), Data :: term()," n> + "[gen_statem:action()] | gen_statem:action()} |" n> + "ignore |" n> + "{stop, Reason :: term()}." n + "init([]) ->" n> + "{state_functions, state_name, #data{}}." n + n + (erlang-skel-separator-start 2) + "%% @private" n + "%% @doc" n + "%% If the gen_statem runs with CallbackMode =:= state_functions" n + "%% there should be one instance of this function for each possible" n + "%% state name. Whenever a gen_statem receives an event," n + "%% the instance of this function with the same name" n + "%% as the current state name StateName is called to" n + "%% handle the event." n + (erlang-skel-separator-end 2) + "-spec state_name(" n> + "gen_statem:event_type(), Msg :: term()," n> + "Data :: term()) ->" n> + "gen_statem:state_function_result(). " n + "state_name({call,Caller}, _Msg, Data) ->" n> + "{next_state, state_name, Data, [{reply,Caller,ok}]}." n + n + (erlang-skel-separator-start 2) + "%% @private" n + "%% @doc" n + "%% If the gen_statem runs with CallbackMode =:= handle_event_function" n + "%% this function is called for every event a gen_statem receives." n + (erlang-skel-separator-end 2) + "-spec handle_event(" n> + "gen_statem:event_type(), Msg :: term()," n> + "State :: term(), Data :: term()) ->" n> + "gen_statem:handle_event_result(). " n + "handle_event({call,From}, _Msg, State, Data) ->" n> + "{next_state, State, Data, [{reply,From,ok}]}." n + n + (erlang-skel-separator-start 2) + "%% @private" n + "%% @doc" n + "%% This function is called by a gen_statem when it is about to" n + "%% terminate. It should be the opposite of Module:init/1 and do any" n + "%% necessary cleaning up. When it returns, the gen_statem terminates with" n + "%% Reason. The return value is ignored." n + (erlang-skel-separator-end 2) + "-spec terminate(Reason :: term(), State :: term(), Data :: term()) ->" n> + "any()." n + "terminate(_Reason, _State, _Data) ->" n> + "void." n + n + (erlang-skel-separator-start 2) + "%% @private" n + "%% @doc" n + "%% Convert process state when code is changed" n + (erlang-skel-separator-end 2) + "-spec code_change(" n> + "OldVsn :: term() | {down,term()}," n> + "State :: term(), Data :: term(), Extra :: term()) ->" n> + "{ok, NewState :: term(), NewData :: term()}." n + "code_change(_OldVsn, State, Data, _Extra) ->" n> + "{ok, State, Data}." n + n + (erlang-skel-double-separator-start 3) + "%%% Internal functions" n + (erlang-skel-double-separator-end 3) + ) + "*The template of a gen_statem. +Please see the function `tempo-define-template'.") + (defvar erlang-skel-wx-object '((erlang-skel-include erlang-skel-large-header) "-behaviour(wx_object)." n n @@ -1070,7 +1188,7 @@ Please see the function `tempo-define-template'.") "%% Note: This directive should only be used in test suites." n "-compile(export_all)." n n - "-include_lib(\"test_server/include/test_server.hrl\")." n n + "-include_lib(\"common_test/include/ct.hrl\")." n n (erlang-skel-separator-start 2) "%% TEST SERVER CALLBACK FUNCTIONS" n @@ -1235,7 +1353,7 @@ Please see the function `tempo-define-template'.") "Config." n n (erlang-skel-separator-start 2) - "%% @spec end_per_suite(Config0) -> void() | {save_config,Config1}" n + "%% @spec end_per_suite(Config0) -> term() | {save_config,Config1}" n "%% Config0 = Config1 = [tuple()]" n (erlang-skel-separator-end 2) "end_per_suite(_Config) ->" n > @@ -1253,7 +1371,7 @@ Please see the function `tempo-define-template'.") (erlang-skel-separator-start 2) "%% @spec end_per_group(GroupName, Config0) ->" n - "%% void() | {save_config,Config1}" n + "%% term() | {save_config,Config1}" n "%% GroupName = atom()" n "%% Config0 = Config1 = [tuple()]" n (erlang-skel-separator-end 2) @@ -1272,7 +1390,7 @@ Please see the function `tempo-define-template'.") (erlang-skel-separator-start 2) "%% @spec end_per_testcase(TestCase, Config0) ->" n - "%% void() | {save_config,Config1} | {fail,Reason}" n + "%% term() | {save_config,Config1} | {fail,Reason}" n "%% TestCase = atom()" n "%% Config0 = Config1 = [tuple()]" n "%% Reason = term()" n @@ -1413,7 +1531,7 @@ Please see the function `tempo-define-template'.") "%% A list of key/value pairs, holding configuration data for the group." n "%%" n "%% @spec end_per_group(GroupName, Config0) ->" n - "%% void() | {save_config,Config1}" n + "%% term() | {save_config,Config1}" n (erlang-skel-separator-end 2) "end_per_group(_GroupName, _Config) ->" n > "ok." n n @@ -1447,7 +1565,7 @@ Please see the function `tempo-define-template'.") "%% A list of key/value pairs, holding the test case configuration." n "%%" n "%% @spec end_per_testcase(TestCase, Config0) ->" n - "%% void() | {save_config,Config1} | {fail,Reason}" n + "%% term() | {save_config,Config1} | {fail,Reason}" n (erlang-skel-separator-end 2) "end_per_testcase(_TestCase, _Config) ->" n > "ok." n n diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el index 0c003bab39..0a3fc0ddff 100644 --- a/lib/tools/emacs/erlang.el +++ b/lib/tools/emacs/erlang.el @@ -7,18 +7,19 @@ ;; %CopyrightBegin% ;; -;; Copyright Ericsson AB 1996-2014. All Rights Reserved. +;; Copyright Ericsson AB 1996-2016. All Rights Reserved. ;; -;; The contents of this file are subject to the Erlang Public License, -;; Version 1.1, (the "License"); you may not use this file except in -;; compliance with the License. You should have received a copy of the -;; Erlang Public License along with this software. If not, it can be -;; retrieved online at http://www.erlang.org/. +;; 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 ;; -;; Software distributed under the License is distributed on an "AS IS" -;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -;; the License for the specific language governing rights and limitations -;; under the License. +;; 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. ;; ;; %CopyrightEnd% ;; @@ -880,10 +881,10 @@ resulting regexp is surrounded by \\_< and \\_>." "dt_restore_tag" "dt_spread_tag" "dunlink" + "convert_time_unit" "external_size" "finish_after_on_load" "finish_loading" - "flush_monitor_message" "format_cpu_topology" "fun_info" "fun_info_mfa" @@ -896,6 +897,7 @@ resulting regexp is surrounded by \\_< and \\_>." "get_module_info" "get_stacktrace" "hash" + "has_prepared_code_on_load" "hibernate" "insert_element" "is_builtin" @@ -913,6 +915,7 @@ resulting regexp is surrounded by \\_< and \\_>." "memory" "module_info" "monitor_node" + "monotonic_time" "nif_error" "phash" "phash2" @@ -946,13 +949,17 @@ resulting regexp is surrounded by \\_< and \\_>." "system_info" "system_monitor" "system_profile" + "system_time" "trace" "trace_delivered" "trace_info" "trace_pattern" + "time_offset" + "timestamp" "universaltime" "universaltime_to_localtime" "universaltime_to_posixtime" + "unique_integer" "yield") "Erlang built-in functions (BIFs) that needs erlang: prefix")) @@ -1338,7 +1345,7 @@ Lock syntax table. The effect is that `apply' in the atom ;;;###autoload -(defun erlang-mode () +(define-derived-mode erlang-mode prog-mode "Erlang" "Major mode for editing Erlang source files in Emacs. It knows about syntax and comment, it can indent code, it is capable of fontifying the source file, the TAGS commands are aware of Erlang @@ -1397,12 +1404,9 @@ and examples of hooks. Other commands: \\{erlang-mode-map}" - (interactive) - (kill-all-local-variables) - (setq major-mode 'erlang-mode) - (setq mode-name "Erlang") + ;; Use our own syntax table function + :syntax-table nil (erlang-syntax-table-init) - (use-local-map erlang-mode-map) (erlang-electric-init) (erlang-menu-init) (erlang-mode-variables) @@ -1412,12 +1416,8 @@ Other commands: (erlang-font-lock-init) (erlang-skel-init) (tempo-use-tag-list 'erlang-tempo-tags) - (run-hooks 'erlang-mode-hook) (if (zerop (buffer-size)) - (run-hooks 'erlang-new-file-hook)) - ;; Doesn't exist in Emacs v21.4; required by Emacs v23. - (if (boundp 'after-change-major-mode-hook) - (run-hooks 'after-change-major-mode-hook))) + (run-hooks 'erlang-new-file-hook))) ;;;###autoload (dolist (r '("\\.erl$" "\\.app\\.src$" "\\.escript" @@ -2444,7 +2444,10 @@ This is automagically called by the user level function `indent-region'." ;; Parse the Erlang code from the beginning of the clause to ;; the beginning of the region. (while (< (point) indent-point) - (setq state (erlang-partial-parse (point) indent-point state))) + (let ((pt (point))) + (setq state (erlang-partial-parse pt indent-point state)) + (if (= pt (point)) + (error "Illegal syntax")))) ;; Indent every line in the region (while continue (goto-char indent-point) @@ -2480,8 +2483,11 @@ This is automagically called by the user level function `indent-region'." (if (>= from-end (- (point-max) indent-point)) (setq continue nil) (while (< (point) indent-point) - (setq state (erlang-partial-parse - (point) indent-point state)))))))) + (let ((pt (point))) + (setq state (erlang-partial-parse + pt indent-point state)) + (if (= pt (point)) + (error "Illegal syntax"))))))))) (defun erlang-indent-current-buffer () @@ -2528,7 +2534,10 @@ Return nil if line starts inside string, t if in a comment." (goto-char parse-start) (erlang-beginning-of-clause)) (while (< (point) indent-point) - (setq state (erlang-partial-parse (point) indent-point state))) + (let ((pt (point))) + (setq state (erlang-partial-parse pt indent-point state)) + (if (= pt (point)) + (error "Illegal syntax")))) (erlang-calculate-stack-indent indent-point state)))) (defun erlang-show-syntactic-information () @@ -2698,12 +2707,13 @@ Value is list (stack token-start token-type in-what)." (erlang-push (list '|| token (current-column)) stack) (forward-char 2)) - ;; Bit-syntax open paren - ((looking-at "<<") + ;; Bit-syntax open. Note that map syntax allows "<<" to follow ":=" + ;; or "=>" without intervening whitespace, so handle that case here + ((looking-at "\\(:=\\|=>\\)?<<") (erlang-push (list '<< token (current-column)) stack) - (forward-char 2)) + (forward-char (- (match-end 0) (match-beginning 0)))) - ;; Bbit-syntax close paren + ;; Bit-syntax close ((looking-at ">>") (while (memq (car (car stack)) '(|| ->)) (erlang-pop stack)) @@ -4188,7 +4198,10 @@ This function is designed to be a member of a criteria list." ;; Do not return `stop' when inside a list comprehension ;; construction. (The point must be after `||'). (while (< (point) orig-point) - (setq state (erlang-partial-parse (point) orig-point state))) + (let ((pt (point))) + (setq state (erlang-partial-parse pt orig-point state)) + (if (= pt (point)) + (error "Illegal syntax")))) (if (and (car state) (eq (car (car (car state))) '||)) nil 'stop))) @@ -4217,7 +4230,7 @@ This function is designed to be a member of a criteria list." This function is designed to be a member of a criteria list." (save-excursion (beginning-of-line) - (when (save-match-data (looking-at "-\\(spec\\|type\\)")) + (when (save-match-data (looking-at "-\\(spec\\|type\\|callback\\)")) 'stop))) diff --git a/lib/tools/emacs/internal_doc/emacs.sgml b/lib/tools/emacs/internal_doc/emacs.sgml index 5b28928605..eb6c3b7bb4 100644 --- a/lib/tools/emacs/internal_doc/emacs.sgml +++ b/lib/tools/emacs/internal_doc/emacs.sgml @@ -1,15 +1,16 @@ <!DOCTYPE CHAPTER PUBLIC "-//Stork//DTD chapter//EN"> <!-- - ``The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved via the world wide web at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + ``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. The Initial Developer of the Original Code is Ericsson Utvecklings AB. Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings diff --git a/lib/tools/emacs/test.erl.indented b/lib/tools/emacs/test.erl.indented index 1c1086ca58..6913068133 100644 --- a/lib/tools/emacs/test.erl.indented +++ b/lib/tools/emacs/test.erl.indented @@ -2,18 +2,19 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2012. All Rights Reserved. +%% Copyright Ericsson AB 2009-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% 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 %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% @@ -32,6 +33,14 @@ -module(test). -compile(export_all). +%% Used to cause an "Unbalanced parentheses" error. +foo(M) -> + M#{a :=<<"a">> + ,b:=1}. +foo() -> + #{a =><<"a">> + ,b=>1}. + %% Module attributes should be highlighted -export([t/1]). diff --git a/lib/tools/emacs/test.erl.orig b/lib/tools/emacs/test.erl.orig index a9d09000d2..621948cbe1 100644 --- a/lib/tools/emacs/test.erl.orig +++ b/lib/tools/emacs/test.erl.orig @@ -2,18 +2,19 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2012. All Rights Reserved. +%% Copyright Ericsson AB 2009-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% 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 %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% @@ -32,6 +33,14 @@ -module(test). -compile(export_all). +%% Used to cause an "Unbalanced parentheses" error. +foo(M) -> +M#{a :=<<"a">> +,b:=1}. +foo() -> +#{a =><<"a">> +,b=>1}. + %% Module attributes should be highlighted -export([t/1]). diff --git a/lib/tools/examples/Makefile b/lib/tools/examples/Makefile index fc14ee54d6..0fcc66d874 100644 --- a/lib/tools/examples/Makefile +++ b/lib/tools/examples/Makefile @@ -1,13 +1,14 @@ -# ``The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved via the world wide web at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. +# ``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. # # The Initial Developer of the Original Code is Ericsson Utvecklings AB. # Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings diff --git a/lib/tools/priv/.gitignore b/lib/tools/priv/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/tools/priv/.gitignore diff --git a/lib/tools/priv/Makefile b/lib/tools/priv/Makefile deleted file mode 100644 index b32ba5820d..0000000000 --- a/lib/tools/priv/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -# ``The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved via the world wide web at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# The Initial Developer of the Original Code is Ericsson Utvecklings AB. -# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings -# AB. All Rights Reserved.'' -# -# $Id$ -# -include $(ERL_TOP)/make/target.mk -include $(ERL_TOP)/make/$(TARGET)/otp.mk - -# ---------------------------------------------------- -# Application version -# ---------------------------------------------------- -include ../vsn.mk -VSN = $(TOOLS_VSN) - -# ---------------------------------------------------- -# Release directory specification -# ---------------------------------------------------- -RELSYSDIR = $(RELEASE_PATH)/lib/tools-$(VSN) - -# ---------------------------------------------------- -# Target Specs -# ---------------------------------------------------- - -HTDOCS_FILES = index.html - -TOOL_FILES = cover.tool - -# ---------------------------------------------------- -# FLAGS -# ---------------------------------------------------- -ERL_COMPILE_FLAGS += - -# ---------------------------------------------------- -# Targets -# ---------------------------------------------------- - -debug opt: - -clean: - -docs: - -# ---------------------------------------------------- -# Release Target -# ---------------------------------------------------- -include $(ERL_TOP)/make/otp_release_targets.mk - -release_spec: opt - $(INSTALL_DIR) "$(RELSYSDIR)/priv" - $(INSTALL_DATA) $(HTDOCS_FILES) "$(RELSYSDIR)/priv" - $(INSTALL_DATA) $(TOOL_FILES) "$(RELSYSDIR)/priv" - -release_docs_spec: - - - diff --git a/lib/tools/priv/cover.tool b/lib/tools/priv/cover.tool deleted file mode 100644 index 9e72f89ff4..0000000000 --- a/lib/tools/priv/cover.tool +++ /dev/null @@ -1,2 +0,0 @@ -{version,"1.2"}. -[{config_func,{cover_web,configData,[]}}]. diff --git a/lib/tools/priv/index.html b/lib/tools/priv/index.html deleted file mode 100644 index 6b60ef5d0a..0000000000 --- a/lib/tools/priv/index.html +++ /dev/null @@ -1,10 +0,0 @@ -<HTML> -<HEAD> -<TITLE>Erlang webb tools </TITLE> -</HEAD> -<FRAMESET COLS="250,*"> -<FRAME NAME="menu" SRC="/webcover/erl/cover_web/menu_frame"> -<FRAME NAME="main" SRC="/webcover/erl/cover_web/compile_frame"> -</FRAMESET> -</HTML> - diff --git a/lib/tools/src/Makefile b/lib/tools/src/Makefile index e606b97a48..032bd612db 100644 --- a/lib/tools/src/Makefile +++ b/lib/tools/src/Makefile @@ -1,18 +1,19 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2013. All Rights Reserved. +# Copyright Ericsson AB 1996-2016. All Rights Reserved. # -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. +# 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 # -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. +# 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. # # %CopyrightEnd% # @@ -36,7 +37,6 @@ RELSYSDIR = $(RELEASE_PATH)/lib/tools-$(VSN) MODULES= \ cover \ - cover_web \ eprof \ fprof \ cprof \ diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl index 31754015f7..69331732bf 100644 --- a/lib/tools/src/cover.erl +++ b/lib/tools/src/cover.erl @@ -1,27 +1,26 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2013. All Rights Reserved. +%% Copyright Ericsson AB 2001-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% 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 %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% -module(cover). %% -%% This module implements the Erlang coverage tool. The module named -%% cover_web implements a user interface for the coverage tool to run -%% under webtool. +%% This module implements the Erlang coverage tool. %% %% ARCHITECTURE %% The coverage tool consists of one process on each node involved in @@ -77,8 +76,11 @@ compile/1, compile/2, compile_module/1, compile_module/2, compile_directory/0, compile_directory/1, compile_directory/2, compile_beam/1, compile_beam_directory/0, compile_beam_directory/1, - analyse/1, analyse/2, analyse/3, analyze/1, analyze/2, analyze/3, + analyse/0, analyse/1, analyse/2, analyse/3, + analyze/0, analyze/1, analyze/2, analyze/3, + analyse_to_file/0, analyse_to_file/1, analyse_to_file/2, analyse_to_file/3, + analyze_to_file/0, analyze_to_file/1, analyze_to_file/2, analyze_to_file/3, async_analyse_to_file/1,async_analyse_to_file/2, async_analyse_to_file/3, async_analyze_to_file/1, @@ -109,6 +111,7 @@ line = '_' % integer() }). -define(BUMP_REC_NAME,bump). +-define(CHUNK_SIZE, 20000). -record(vars, {module, % atom() Module name @@ -132,7 +135,7 @@ -define(SERVER, cover_server). %% Line doesn't matter. --define(BLOCK(Expr), {block,0,[Expr]}). +-define(BLOCK(Expr), {block,erl_anno:new(0),[Expr]}). -define(BLOCK1(Expr), if element(1, Expr) =:= block -> @@ -181,10 +184,11 @@ start(Node) when is_atom(Node) -> start(Nodes) -> call({start_nodes,remove_myself(Nodes,[])}). -%% compile(ModFile) -> -%% compile(ModFile, Options) -> -%% compile_module(ModFile) -> Result -%% compile_module(ModFile, Options) -> Result +%% compile(ModFiles) -> +%% compile(ModFiles, Options) -> +%% compile_module(ModFiles) -> Result +%% compile_module(ModFiles, Options) -> Result +%% ModFiles = ModFile | [ModFile] %% ModFile = Module | File %% Module = atom() %% File = string() @@ -198,18 +202,27 @@ compile(ModFile, Options) -> compile_module(ModFile) when is_atom(ModFile); is_list(ModFile) -> compile_module(ModFile, []). -compile_module(Module, Options) when is_atom(Module), is_list(Options) -> - compile_module(atom_to_list(Module), Options); -compile_module(File, Options) when is_list(File), is_list(Options) -> - WithExt = case filename:extension(File) of - ".erl" -> - File; - _ -> - File++".erl" - end, - AbsFile = filename:absname(WithExt), - [R] = compile_modules([AbsFile], Options), - R. +compile_module(ModFile, Options) when is_atom(ModFile); + is_list(ModFile), is_integer(hd(ModFile)) -> + [R] = compile_module([ModFile], Options), + R; +compile_module(ModFiles, Options) when is_list(Options) -> + AbsFiles = + [begin + File = + case ModFile of + _ when is_atom(ModFile) -> atom_to_list(ModFile); + _ when is_list(ModFile) -> ModFile + end, + WithExt = case filename:extension(File) of + ".erl" -> + File; + _ -> + File++".erl" + end, + filename:absname(WithExt) + end || ModFile <- ModFiles], + compile_modules(AbsFiles, Options). %% compile_directory() -> %% compile_directory(Dir) -> @@ -240,13 +253,14 @@ compile_directory(Dir, Options) when is_list(Dir), is_list(Options) -> compile_modules(Files,Options) -> Options2 = filter_options(Options), - compile_modules(Files,Options2,[]). + %% compile_modules(Files,Options2,[]). + call({compile, Files, Options2}). -compile_modules([File|Files], Options, Result) -> - R = call({compile, File, Options}), - compile_modules(Files,Options,[R|Result]); -compile_modules([],_Opts,Result) -> - lists:reverse(Result). +%% compile_modules([File|Files], Options, Result) -> +%% R = call({compile, File, Options}), +%% compile_modules(Files,Options,[R|Result]); +%% compile_modules([],_Opts,Result) -> +%% lists:reverse(Result). filter_options(Options) -> lists:filter(fun(Option) -> @@ -264,30 +278,17 @@ filter_options(Options) -> %% ModFile - see compile/1 %% Result - see compile/1 %% Reason = non_existing | already_cover_compiled -compile_beam(Module) when is_atom(Module) -> - case code:which(Module) of - non_existing -> +compile_beam(ModFile0) when is_atom(ModFile0); + is_list(ModFile0), is_integer(hd(ModFile0)) -> + case compile_beams([ModFile0]) of + [{error,{non_existing,_}}] -> + %% Backwards compatibility {error,non_existing}; - ?TAG -> - compile_beam(Module,?TAG); - File -> - compile_beam(Module,File) + [Result] -> + Result end; -compile_beam(File) when is_list(File) -> - {WithExt,WithoutExt} - = case filename:rootname(File,".beam") of - File -> - {File++".beam",File}; - Rootname -> - {File,Rootname} - end, - AbsFile = filename:absname(WithExt), - Module = list_to_atom(filename:basename(WithoutExt)), - compile_beam(Module,AbsFile). - -compile_beam(Module,File) -> - call({compile_beam,Module,File}). - +compile_beam(ModFiles) when is_list(ModFiles) -> + compile_beams(ModFiles). %% compile_beam_directory(Dir) -> [Result] | {error,Reason} @@ -312,19 +313,52 @@ compile_beam_directory(Dir) when is_list(Dir) -> Error end. -compile_beams(Files) -> - compile_beams(Files,[]). -compile_beams([File|Files],Result) -> - R = compile_beam(File), - compile_beams(Files,[R|Result]); -compile_beams([],Result) -> - lists:reverse(Result). - +compile_beams(ModFiles0) -> + ModFiles = get_mods_and_beams(ModFiles0,[]), + call({compile_beams,ModFiles}). -%% analyse(Module) -> -%% analyse(Module, Analysis) -> -%% analyse(Module, Level) -> -%% analyse(Module, Analysis, Level) -> {ok,Answer} | {error,Error} +get_mods_and_beams([Module|ModFiles],Acc) when is_atom(Module) -> + case code:which(Module) of + non_existing -> + get_mods_and_beams(ModFiles,[{error,{non_existing,Module}}|Acc]); + File -> + get_mods_and_beams([{Module,File}|ModFiles],Acc) + end; +get_mods_and_beams([File|ModFiles],Acc) when is_list(File) -> + {WithExt,WithoutExt} + = case filename:rootname(File,".beam") of + File -> + {File++".beam",File}; + Rootname -> + {File,Rootname} + end, + AbsFile = filename:absname(WithExt), + Module = list_to_atom(filename:basename(WithoutExt)), + get_mods_and_beams([{Module,AbsFile}|ModFiles],Acc); +get_mods_and_beams([{Module,File}|ModFiles],Acc) -> + %% Check for duplicates + case lists:keyfind(Module,2,Acc) of + {ok,Module,File} -> + %% Duplicate, but same file so ignore + get_mods_and_beams(ModFiles,Acc); + {ok,Module,_OtherFile} -> + %% Duplicate and differnet file - error + get_mods_and_beams(ModFiles,[{error,{duplicate,Module}}|Acc]); + _ -> + get_mods_and_beams(ModFiles,[{ok,Module,File}|Acc]) + end; +get_mods_and_beams([],Acc) -> + lists:reverse(Acc). + + +%% analyse(Modules) -> +%% analyse(Analysis) -> +%% analyse(Level) -> +%% analyse(Modules, Analysis) -> +%% analyse(Modules, Level) -> +%% analyse(Analysis, Level) +%% analyse(Modules, Analysis, Level) -> {ok,Answer} | {error,Error} +%% Modules = Module | [Module] %% Module = atom() %% Analysis = coverage | calls %% Level = line | clause | function | module @@ -337,48 +371,74 @@ compile_beams([],Result) -> %% N = A = C = integer() %% Value = {Cov,NotCov} | Calls %% Cov = NotCov = Calls = integer() -%% Error = {not_cover_compiled,Module} +%% Error = {not_cover_compiled,Module} | not_main_node +-define(is_analysis(__A__), + (__A__=:=coverage orelse __A__=:=calls)). +-define(is_level(__L__), + (__L__=:=line orelse __L__=:=clause orelse + __L__=:=function orelse __L__=:=module)). +analyse() -> + analyse('_'). + +analyse(Analysis) when ?is_analysis(Analysis) -> + analyse('_', Analysis); +analyse(Level) when ?is_level(Level) -> + analyse('_', Level); analyse(Module) -> analyse(Module, coverage). -analyse(Module, Analysis) when Analysis=:=coverage; Analysis=:=calls -> + +analyse(Analysis, Level) when ?is_analysis(Analysis) andalso + ?is_level(Level) -> + analyse('_', Analysis, Level); +analyse(Module, Analysis) when ?is_analysis(Analysis) -> analyse(Module, Analysis, function); -analyse(Module, Level) when Level=:=line; Level=:=clause; Level=:=function; - Level=:=module -> +analyse(Module, Level) when ?is_level(Level) -> analyse(Module, coverage, Level). -analyse(Module, Analysis, Level) when is_atom(Module), - Analysis=:=coverage; Analysis=:=calls, - Level=:=line; Level=:=clause; - Level=:=function; Level=:=module -> + +analyse(Module, Analysis, Level) when ?is_analysis(Analysis), + ?is_level(Level) -> call({{analyse, Analysis, Level}, Module}). +analyze() -> analyse( ). analyze(Module) -> analyse(Module). analyze(Module, Analysis) -> analyse(Module, Analysis). analyze(Module, Analysis, Level) -> analyse(Module, Analysis, Level). -%% analyse_to_file(Module) -> -%% analyse_to_file(Module, Options) -> -%% analyse_to_file(Module, OutFile) -> -%% analyse_to_file(Module, OutFile, Options) -> {ok,OutFile} | {error,Error} +%% analyse_to_file() -> +%% analyse_to_file(Modules) -> +%% analyse_to_file(Modules, Options) -> +%% Modules = Module | [Module] %% Module = atom() %% OutFile = string() %% Options = [Option] -%% Option = html +%% Option = html | {outfile,filename()} | {outdir,dirname()} %% Error = {not_cover_compiled,Module} | no_source_code_found | %% {file,File,Reason} %% File = string() %% Reason = term() -analyse_to_file(Module) when is_atom(Module) -> - analyse_to_file(Module, outfilename(Module,[]), []). -analyse_to_file(Module, []) when is_atom(Module) -> - analyse_to_file(Module, outfilename(Module,[]), []); -analyse_to_file(Module, Options) when is_atom(Module), - is_list(Options), is_atom(hd(Options)) -> - analyse_to_file(Module, outfilename(Module,Options), Options); -analyse_to_file(Module, OutFile) when is_atom(Module), is_list(OutFile) -> - analyse_to_file(Module, OutFile, []). -analyse_to_file(Module, OutFile, Options) when is_atom(Module), is_list(OutFile) -> - call({{analyse_to_file, OutFile, Options}, Module}). - +%% +%% Kept for backwards compatibility: +%% analyse_to_file(Modules, OutFile) -> +%% analyse_to_file(Modules, OutFile, Options) -> {ok,OutFile} | {error,Error} +analyse_to_file() -> + analyse_to_file('_'). +analyse_to_file(Arg) -> + case is_options(Arg) of + true -> + analyse_to_file('_',Arg); + false -> + analyse_to_file(Arg,[]) + end. +analyse_to_file(Module, OutFile) when is_list(OutFile), is_integer(hd(OutFile)) -> + %% Kept for backwards compatibility + analyse_to_file(Module, [{outfile,OutFile}]); +analyse_to_file(Module, Options) when is_list(Options) -> + call({{analyse_to_file, Options}, Module}). +analyse_to_file(Module, OutFile, Options) when is_list(OutFile) -> + %% Kept for backwards compatibility + analyse_to_file(Module,[{outfile,OutFile}|Options]). + +analyze_to_file() -> analyse_to_file(). analyze_to_file(Module) -> analyse_to_file(Module). analyze_to_file(Module, OptOrOut) -> analyse_to_file(Module, OptOrOut). analyze_to_file(Module, OutFile, Options) -> @@ -391,6 +451,15 @@ async_analyse_to_file(Module, OutFileOrOpts) -> async_analyse_to_file(Module, OutFile, Options) -> do_spawn(?MODULE, analyse_to_file, [Module, OutFile, Options]). +is_options([html]) -> + true; % this is not 100% safe - could be a module named html... +is_options([html|Opts]) -> + is_options(Opts); +is_options([{Opt,_}|_]) when Opt==outfile; Opt==outdir -> + true; +is_options(_) -> + false. + do_spawn(M,F,A) -> spawn_link(fun() -> case apply(M,F,A) of @@ -408,13 +477,16 @@ async_analyze_to_file(Module, OutFileOrOpts) -> async_analyze_to_file(Module, OutFile, Options) -> async_analyse_to_file(Module, OutFile, Options). -outfilename(Module,Opts) -> - case lists:member(html,Opts) of - true -> - atom_to_list(Module)++".COVER.html"; - false -> - atom_to_list(Module)++".COVER.out" - end. +outfilename(undefined, Module, HTML) -> + outfilename(Module, HTML); +outfilename(OutDir, Module, HTML) -> + filename:join(OutDir, outfilename(Module, HTML)). + +outfilename(Module, true) -> + atom_to_list(Module)++".COVER.html"; +outfilename(Module, false) -> + atom_to_list(Module)++".COVER.out". + %% export(File) %% export(File,Module) -> ok | {error,Reason} @@ -559,7 +631,7 @@ init_main(Starter) -> ,{write_concurrency, true} ]), ets:new(?COVER_CLAUSE_TABLE, [set, public, named_table]), - ets:new(?BINARY_TABLE, [set, named_table]), + ets:new(?BINARY_TABLE, [set, public, named_table]), ets:new(?COLLECTION_TABLE, [set, public, named_table]), ets:new(?COLLECTION_CLAUSE_TABLE, [set, public, named_table]), net_kernel:monitor_nodes(true), @@ -573,55 +645,19 @@ main_process_loop(State) -> reply(From, {ok,StartedNodes}), main_process_loop(State1); - {From, {compile, File, Options}} -> - case do_compile(File, Options) of - {ok, Module} -> - remote_load_compiled(State#main_state.nodes,[{Module,File}]), - reply(From, {ok, Module}), - Compiled = add_compiled(Module, File, - State#main_state.compiled), - Imported = remove_imported(Module,State#main_state.imported), - NewState = State#main_state{compiled = Compiled, - imported = Imported}, - %% This module (cover) could have been reloaded. Make - %% sure we run the new code. - ?MODULE:main_process_loop(NewState); - error -> - reply(From, {error, File}), - main_process_loop(State) - end; + {From, {compile, Files, Options}} -> + {R,S} = do_compile(Files, Options, State), + reply(From,R), + %% This module (cover) could have been reloaded. Make + %% sure we run the new code. + ?MODULE:main_process_loop(S); - {From, {compile_beam, Module, BeamFile0}} -> - Compiled0 = State#main_state.compiled, - case get_beam_file(Module,BeamFile0,Compiled0) of - {ok,BeamFile} -> - UserOptions = get_compile_options(Module,BeamFile), - {Reply,Compiled} = - case do_compile_beam(Module,BeamFile,UserOptions) of - {ok, Module} -> - remote_load_compiled(State#main_state.nodes, - [{Module,BeamFile}]), - C = add_compiled(Module,BeamFile,Compiled0), - {{ok,Module},C}; - error -> - {{error, BeamFile}, Compiled0}; - {error,Reason} -> % no abstract code - {{error, {Reason, BeamFile}}, Compiled0} - end, - reply(From,Reply), - Imported = remove_imported(Module,State#main_state.imported), - NewState = State#main_state{compiled = Compiled, - imported = Imported}, - %% This module (cover) could have been reloaded. Make - %% sure we run the new code. - ?MODULE:main_process_loop(NewState); - {error,no_beam} -> - %% The module has first been compiled from .erl, and now - %% someone tries to compile it from .beam - reply(From, - {error,{already_cover_compiled,no_beam_found,Module}}), - main_process_loop(State) - end; + {From, {compile_beams, ModsAndFiles}} -> + {R,S} = do_compile_beams(ModsAndFiles,State), + reply(From,R), + %% This module (cover) could have been reloaded. Make + %% sure we run the new code. + ?MODULE:main_process_loop(S); {From, {export,OutFile,Module}} -> spawn(fun() -> @@ -706,6 +742,16 @@ main_process_loop(State) -> unregister(?SERVER), reply(From, ok); + {From, {{analyse, Analysis, Level}, '_'}} -> + R = analyse_all(Analysis, Level, State), + reply(From, R), + main_process_loop(State); + + {From, {{analyse, Analysis, Level}, Modules}} when is_list(Modules) -> + R = analyse_list(Modules, Analysis, Level, State), + reply(From, R), + main_process_loop(State); + {From, {{analyse, Analysis, Level}, Module}} -> S = try Loaded = is_loaded(Module, State), @@ -722,15 +768,23 @@ main_process_loop(State) -> end, main_process_loop(S); - {From, {{analyse_to_file, OutFile, Opts},Module}} -> + {From, {{analyse_to_file, Opts},'_'}} -> + R = analyse_all_to_file(Opts, State), + reply(From,R), + main_process_loop(State); + + {From, {{analyse_to_file, Opts},Modules}} when is_list(Modules) -> + R = analyse_list_to_file(Modules, Opts, State), + reply(From,R), + main_process_loop(State); + + {From, {{analyse_to_file, Opts},Module}} -> S = try Loaded = is_loaded(Module, State), - spawn(fun() -> - ?SPAWN_DBG(analyse_to_file, - {Module,OutFile, Opts}), + spawn_link(fun() -> + ?SPAWN_DBG(analyse_to_file,{Module,Opts}), do_parallel_analysis_to_file( - Module, OutFile, Opts, - Loaded, From, State) + Module, Opts, Loaded, From, State) end), State catch throw:Reason -> @@ -848,11 +902,15 @@ remote_process_loop(State) -> {remote,collect,Module,CollectorPid} -> self() ! {remote,collect,Module,CollectorPid, ?SERVER}; - {remote,collect,Module,CollectorPid,From} -> + {remote,collect,Modules0,CollectorPid,From} -> + Modules = case Modules0 of + '_' -> [M || {M,_} <- State#remote_state.compiled]; + _ -> Modules0 + end, spawn(fun() -> ?SPAWN_DBG(remote_collect, - {Module, CollectorPid, From}), - do_collect(Module, CollectorPid, From) + {Modules, CollectorPid, From}), + do_collect(Modules, CollectorPid, From) end), remote_process_loop(State); @@ -893,39 +951,51 @@ remote_process_loop(State) -> end. -do_collect(Module, CollectorPid, From) -> - AllMods = - case Module of - '_' -> ets:tab2list(?COVER_CLAUSE_TABLE); - _ -> ets:lookup(?COVER_CLAUSE_TABLE, Module) - end, - - %% Sending clause by clause in order to avoid large lists +do_collect(Modules, CollectorPid, From) -> pmap( - fun({_Mod,Clauses}) -> - lists:map(fun(Clause) -> - send_collected_data(Clause, CollectorPid) - end,Clauses) - end,AllMods), + fun(Module) -> + Pattern = {#bump{module=Module, _='_'}, '$1'}, + MatchSpec = [{Pattern,[{'=/=','$1',0}],['$_']}], + Match = ets:select(?COVER_TABLE,MatchSpec,?CHUNK_SIZE), + send_chunks(Match, CollectorPid, []) + end,Modules), CollectorPid ! done, remote_reply(From, ok). -send_collected_data({M,F,A,C,_L}, CollectorPid) -> - Pattern = - {#bump{module=M, function=F, arity=A, clause=C}, '_'}, - Bumps = ets:match_object(?COVER_TABLE, Pattern), - %% Reset - lists:foreach(fun({Bump,_N}) -> - ets:insert(?COVER_TABLE, {Bump,0}) - end, - Bumps), - CollectorPid ! {chunk,Bumps}. +send_chunks('$end_of_table', _CollectorPid, Mons) -> + get_downs(Mons); +send_chunks({Chunk,Continuation}, CollectorPid, Mons) -> + Mon = spawn_monitor( + fun() -> + lists:foreach(fun({Bump,_N}) -> + ets:insert(?COVER_TABLE, {Bump,0}) + end, + Chunk) end), + send_chunk(CollectorPid,Chunk), + send_chunks(ets:select(Continuation), CollectorPid, [Mon|Mons]). + +send_chunk(CollectorPid,Chunk) -> + CollectorPid ! {chunk,Chunk,self()}, + receive continue -> ok end. + +get_downs([]) -> + ok; +get_downs(Mons) -> + receive + {'DOWN', Ref, _Type, Pid, _Reason} = Down -> + case lists:member({Pid,Ref},Mons) of + true -> + get_downs(lists:delete({Pid,Ref},Mons)); + false -> + %% This should be handled somewhere else + self() ! Down, + get_downs(Mons) + end + end. -reload_originals([{Module,_File}|Compiled]) -> - do_reload_original(Module), - reload_originals(Compiled); -reload_originals([]) -> - ok. +reload_originals(Compiled) -> + Modules = [M || {M,_} <- Compiled], + pmap(fun do_reload_original/1, Modules). do_reload_original(Module) -> case code:which(Module) of @@ -946,14 +1016,24 @@ load_compiled([{Module,File,Binary,InitialTable}|Compiled],Acc) -> %% Make sure the #bump{} records are available *before* the %% module is loaded. insert_initial_data(InitialTable), - NewAcc = - case code:load_binary(Module, ?TAG, Binary) of - {module,Module} -> - add_compiled(Module, File, Acc); - _ -> - do_clear(Module), - Acc - end, + Sticky = case code:is_sticky(Module) of + true -> + code:unstick_mod(Module), + true; + false -> + false + end, + NewAcc = case code:load_binary(Module, ?TAG, Binary) of + {module,Module} -> + add_compiled(Module, File, Acc); + _ -> + do_clear(Module), + Acc + end, + case Sticky of + true -> code:stick_mod(Module); + false -> ok + end, load_compiled(Compiled,NewAcc); load_compiled([],Acc) -> Acc. @@ -1068,15 +1148,40 @@ remote_load_compiled(_Nodes, [], [], _ModNum) -> ok; remote_load_compiled(Nodes, Compiled, Acc, ModNum) when Compiled == []; ModNum == ?MAX_MODS -> + RemoteLoadData = get_downs_r(Acc), lists:foreach( fun(Node) -> - remote_call(Node,{remote,load_compiled,Acc}) + remote_call(Node,{remote,load_compiled,RemoteLoadData}) end, Nodes), remote_load_compiled(Nodes, Compiled, [], 0); remote_load_compiled(Nodes, [MF | Rest], Acc, ModNum) -> remote_load_compiled( - Nodes, Rest, [get_data_for_remote_loading(MF) | Acc], ModNum + 1). + Nodes, Rest, + [spawn_job_r(fun() -> get_data_for_remote_loading(MF) end) | Acc], + ModNum + 1). + +spawn_job_r(Fun) -> + spawn_monitor(fun() -> exit(Fun()) end). + +get_downs_r([]) -> + []; +get_downs_r(Mons) -> + receive + {'DOWN', Ref, _Type, Pid, R={_,_,_,_}} -> + [R|get_downs_r(lists:delete({Pid,Ref},Mons))]; + {'DOWN', Ref, _Type, Pid, Reason} = Down -> + case lists:member({Pid,Ref},Mons) of + true -> + %% Something went really wrong - don't hang! + exit(Reason); + false -> + %% This should be handled somewhere else + self() ! Down, + get_downs_r(Mons) + end + end. + %% Read all data needed for loading a cover compiled module on a remote node %% Binary is the beam code for the module and InitialTable is the initial @@ -1113,11 +1218,11 @@ remote_reset(Module,Nodes) -> Nodes). %% Collect data from remote nodes - used for analyse or stop(Node) -remote_collect(Module,Nodes,Stop) -> +remote_collect(Modules,Nodes,Stop) -> pmap(fun(Node) -> ?SPAWN_DBG(remote_collect, - {Module, Nodes, Stop}), - do_collection(Node, Module, Stop) + {Modules, Nodes, Stop}), + do_collection(Node, Modules, Stop) end, Nodes). @@ -1138,8 +1243,9 @@ do_collection(Node, Module, Stop) -> collector_proc() -> ?SPAWN_DBG(collector_proc, []), receive - {chunk,Chunk} -> + {chunk,Chunk,From} -> insert_in_collection_table(Chunk), + From ! continue, collector_proc(); done -> ok @@ -1259,6 +1365,19 @@ add_compiled(Module, File, [H|Compiled]) -> add_compiled(Module, File, []) -> [{Module,File}]. +are_loaded([Module|Modules], State, Loaded, Imported, Error) -> + try is_loaded(Module,State) of + {loaded,File} -> + are_loaded(Modules, State, [{Module,File}|Loaded], Imported, Error); + {imported,File,_} -> + are_loaded(Modules, State, Loaded, [{Module,File}|Imported], Error) + catch throw:_ -> + are_loaded(Modules, State, Loaded, Imported, + [{not_cover_compiled,Module}|Error]) + end; +are_loaded([], _State, Loaded, Imported, Error) -> + {Loaded, Imported, Error}. + is_loaded(Module, State) -> case get_file(Module, State#main_state.compiled) of {ok, File} -> @@ -1333,18 +1452,75 @@ get_compiled_still_loaded(Nodes,Compiled0) -> %%%--Compilation--------------------------------------------------------- -%% do_compile(File, Options) -> {ok,Module} | {error,Error} -do_compile(File, UserOptions) -> +do_compile_beams(ModsAndFiles, State) -> + Result0 = pmap(fun({ok,Module,File}) -> + do_compile_beam(Module,File,State); + (Error) -> + Error + end, + ModsAndFiles), + Compiled = [{M,F} || {ok,M,F} <- Result0], + remote_load_compiled(State#main_state.nodes,Compiled), + fix_state_and_result(Result0,State,[]). + +do_compile_beam(Module,BeamFile0,State) -> + case get_beam_file(Module,BeamFile0,State#main_state.compiled) of + {ok,BeamFile} -> + UserOptions = get_compile_options(Module,BeamFile), + case do_compile_beam1(Module,BeamFile,UserOptions) of + {ok, Module} -> + {ok,Module,BeamFile}; + error -> + {error, BeamFile}; + {error,Reason} -> % no abstract code or no 'file' attribute + {error, {Reason, BeamFile}} + end; + {error,no_beam} -> + %% The module has first been compiled from .erl, and now + %% someone tries to compile it from .beam + {error,{already_cover_compiled,no_beam_found,Module}} + end. + +fix_state_and_result([{ok,Module,BeamFile}|Rest],State,Acc) -> + Compiled = add_compiled(Module,BeamFile,State#main_state.compiled), + Imported = remove_imported(Module,State#main_state.imported), + NewState = State#main_state{compiled=Compiled,imported=Imported}, + fix_state_and_result(Rest,NewState,[{ok,Module}|Acc]); +fix_state_and_result([Error|Rest],State,Acc) -> + fix_state_and_result(Rest,State,[Error|Acc]); +fix_state_and_result([],State,Acc) -> + {lists:reverse(Acc),State}. + + +do_compile(Files, Options, State) -> + Result0 = pmap(fun(File) -> + do_compile(File, Options) + end, + Files), + Compiled = [{M,F} || {ok,M,F} <- Result0], + remote_load_compiled(State#main_state.nodes,Compiled), + fix_state_and_result(Result0,State,[]). + +do_compile(File, Options) -> + case do_compile1(File, Options) of + {ok, Module} -> + {ok,Module,File}; + error -> + {error,File} + end. + +%% do_compile1(File, Options) -> {ok,Module} | error +do_compile1(File, UserOptions) -> Options = [debug_info,binary,report_errors,report_warnings] ++ UserOptions, case compile:file(File, Options) of {ok, Module, Binary} -> - do_compile_beam(Module,Binary,UserOptions); + do_compile_beam1(Module,Binary,UserOptions); error -> error end. %% Beam is a binary or a .beam file name -do_compile_beam(Module,Beam,UserOptions) -> +do_compile_beam1(Module,Beam,UserOptions) -> %% Clear database do_clear(Module), @@ -1359,32 +1535,11 @@ do_compile_beam(Module,Beam,UserOptions) -> {error,E}; {raw_abstract_v1,Code} -> Forms0 = epp:interpret_file_attribute(Code), - {Forms,Vars} = transform(Forms0, Module), - - %% We need to recover the source from the compilation - %% info otherwise the newly compiled module will have - %% source pointing to the current directory - SourceInfo = get_source_info(Module, Beam), - - %% Compile and load the result - %% It's necessary to check the result of loading since it may - %% fail, for example if Module resides in a sticky directory - {ok, Module, Binary} = compile:forms(Forms, SourceInfo ++ UserOptions), - case code:load_binary(Module, ?TAG, Binary) of - {module, Module} -> - - %% Store info about all function clauses in database - InitInfo = lists:reverse(Vars#vars.init_info), - ets:insert(?COVER_CLAUSE_TABLE, {Module, InitInfo}), - - %% Store binary code so it can be loaded on remote nodes - ets:insert(?BINARY_TABLE, {Module, Binary}), - - {ok, Module}; - - _Error -> - do_clear(Module), - error + case find_main_filename(Forms0) of + {ok,MainFile} -> + do_compile_beam2(Module,Beam,UserOptions,Forms0,MainFile); + Error -> + Error end; {_VSN,_Code} -> %% Wrong version of abstract code. Just report that there @@ -1401,6 +1556,35 @@ get_abstract_code(Module, Beam) -> Error -> Error end. +do_compile_beam2(Module,Beam,UserOptions,Forms0,MainFile) -> + {Forms,Vars} = transform(Forms0, Module, MainFile), + + %% We need to recover the source from the compilation + %% info otherwise the newly compiled module will have + %% source pointing to the current directory + SourceInfo = get_source_info(Module, Beam), + + %% Compile and load the result + %% It's necessary to check the result of loading since it may + %% fail, for example if Module resides in a sticky directory + {ok, Module, Binary} = compile:forms(Forms, SourceInfo ++ UserOptions), + case code:load_binary(Module, ?TAG, Binary) of + {module, Module} -> + + %% Store info about all function clauses in database + InitInfo = lists:reverse(Vars#vars.init_info), + ets:insert(?COVER_CLAUSE_TABLE, {Module, InitInfo}), + + %% Store binary code so it can be loaded on remote nodes + ets:insert(?BINARY_TABLE, {Module, Binary}), + + {ok, Module}; + + _Error -> + do_clear(Module), + error + end. + get_source_info(Module, Beam) -> Compile = get_compile_info(Module, Beam), case lists:keyfind(source, 1, Compile) of @@ -1423,8 +1607,7 @@ get_compile_info(Module, Beam) -> [] end. -transform(Code, Module) -> - MainFile=find_main_filename(Code), +transform(Code, Module, MainFile) -> Vars0 = #vars{module=Module}, {ok,MungedForms,Vars} = transform_2(Code,[],Vars0,MainFile,on), {MungedForms,Vars}. @@ -1432,9 +1615,12 @@ transform(Code, Module) -> %% Helpfunction which returns the first found file-attribute, which can %% be interpreted as the name of the main erlang source file. find_main_filename([{attribute,_,file,{MainFile,_}}|_]) -> - MainFile; + {ok,MainFile}; find_main_filename([_|Rest]) -> - find_main_filename(Rest). + find_main_filename(Rest); +find_main_filename([]) -> + {error, no_file_attribute}. + transform_2([Form0|Forms],MungedForms,Vars,MainFile,Switch) -> Form = expand(Form0), @@ -1459,18 +1645,18 @@ expand({clause,Line,Pattern,Guards,Body}, Vs, N) -> expand({op,_Line,'andalso',ExprL,ExprR}, Vs, N) -> {ExpandedExprL,N2} = expand(ExprL, Vs, N), {ExpandedExprR,N3} = expand(ExprR, Vs, N2), - LineL = element(2, ExpandedExprL), + Anno = element(2, ExpandedExprL), {bool_switch(ExpandedExprL, ExpandedExprR, - {atom,LineL,false}, + {atom,Anno,false}, Vs, N3), N3 + 1}; expand({op,_Line,'orelse',ExprL,ExprR}, Vs, N) -> {ExpandedExprL,N2} = expand(ExprL, Vs, N), {ExpandedExprR,N3} = expand(ExprR, Vs, N2), - LineL = element(2, ExpandedExprL), + Anno = element(2, ExpandedExprL), {bool_switch(ExpandedExprL, - {atom,LineL,true}, + {atom,Anno,true}, ExpandedExprR, Vs, N3), N3 + 1}; @@ -1579,7 +1765,7 @@ munge_body(Expr, Vars) -> munge_body([Expr|Body], Vars, MungedBody, LastExprBumpLines) -> %% Here is the place to add a call to cover:bump/6! - Line = element(2, Expr), + Line = erl_anno:line(element(2, Expr)), Lines = Vars#vars.lines, case lists:member(Line,Lines) of true -> % already a bump at this line @@ -1715,17 +1901,18 @@ fix_cls([Cl | Cls], Line, Bump) -> false -> {clause,CL,P,G,Body} = Cl, UniqueVarName = list_to_atom(lists:concat(["$cover$ ",Line])), - V = {var,0,UniqueVarName}, + A = erl_anno:new(0), + V = {var,A,UniqueVarName}, [Last|Rest] = lists:reverse(Body), - Body1 = lists:reverse(Rest, [{match,0,V,Last},Bump,V]), + Body1 = lists:reverse(Rest, [{match,A,V,Last},Bump,V]), [{clause,CL,P,G,Body1} | fix_cls(Cls, Line, Bump)] end. bumps_line(E, L) -> try bumps_line1(E, L) catch true -> true end. -bumps_line1({call,0,{remote,0,{atom,0,ets},{atom,0,update_counter}}, - [{atom,0,?COVER_TABLE},{tuple,0,[_,_,_,_,_,{integer,0,Line}]},_]}, +bumps_line1({call,_,{remote,_,{atom,_,ets},{atom,_,update_counter}}, + [{atom,_,?COVER_TABLE},{tuple,_,[_,_,_,_,_,{integer,_,Line}]},_]}, Line) -> throw(true); bumps_line1([E | Es], Line) -> @@ -1739,15 +1926,16 @@ bumps_line1(_, _) -> %%% End of fix of last expression. bump_call(Vars, Line) -> - {call,0,{remote,0,{atom,0,ets},{atom,0,update_counter}}, - [{atom,0,?COVER_TABLE}, - {tuple,0,[{atom,0,?BUMP_REC_NAME}, - {atom,0,Vars#vars.module}, - {atom,0,Vars#vars.function}, - {integer,0,Vars#vars.arity}, - {integer,0,Vars#vars.clause}, - {integer,0,Line}]}, - {integer,0,1}]}. + A = erl_anno:new(0), + {call,A,{remote,A,{atom,A,ets},{atom,A,update_counter}}, + [{atom,A,?COVER_TABLE}, + {tuple,A,[{atom,A,?BUMP_REC_NAME}, + {atom,A,Vars#vars.module}, + {atom,A,Vars#vars.function}, + {integer,A,Vars#vars.arity}, + {integer,A,Vars#vars.clause}, + {integer,A,Line}]}, + {integer,A,1}]}. munge_expr({match,Line,ExprL,ExprR}, Vars) -> {MungedExprL, Vars2} = munge_expr(ExprL, Vars), @@ -1814,9 +2002,7 @@ munge_expr({lc,Line,Expr,Qs}, Vars) -> {MungedQs, Vars3} = munge_qualifiers(Qs, Vars2), {{lc,Line,MungedExpr,MungedQs}, Vars3}; munge_expr({bc,Line,Expr,Qs}, Vars) -> - {bin,BLine,[{bin_element,EL,Val,Sz,TSL}|Es]} = Expr, - Expr2 = {bin,BLine,[{bin_element,EL,?BLOCK1(Val),Sz,TSL}|Es]}, - {MungedExpr,Vars2} = munge_expr(Expr2, Vars), + {MungedExpr,Vars2} = munge_expr(?BLOCK1(Expr), Vars), {MungedQs, Vars3} = munge_qualifiers(Qs, Vars2), {{bc,Line,MungedExpr,MungedQs}, Vars3}; munge_expr({block,Line,Body}, Vars) -> @@ -1915,10 +2101,21 @@ common_elems(L1, L2) -> collect(Nodes) -> %% local node AllClauses = ets:tab2list(?COVER_CLAUSE_TABLE), - pmap(fun move_modules/1,AllClauses), - + Mon1 = spawn_monitor(fun() -> pmap(fun move_modules/1,AllClauses) end), + %% remote nodes - remote_collect('_',Nodes,false). + Mon2 = spawn_monitor(fun() -> remote_collect('_',Nodes,false) end), + get_downs([Mon1,Mon2]). + +%% Collect data for a list of modules +collect(Modules,Nodes) -> + MS = [{{'$1','_'},[{'==','$1',M}],['$_']} || M <- Modules], + Clauses = ets:select(?COVER_CLAUSE_TABLE,MS), + Mon1 = spawn_monitor(fun() -> pmap(fun move_modules/1,Clauses) end), + + %% remote nodes + Mon2 = spawn_monitor(fun() -> remote_collect('_',Nodes,false) end), + get_downs([Mon1,Mon2]). %% Collect data for one module collect(Module,Clauses,Nodes) -> @@ -1926,25 +2123,26 @@ collect(Module,Clauses,Nodes) -> move_modules({Module,Clauses}), %% remote nodes - remote_collect(Module,Nodes,false). + remote_collect([Module],Nodes,false). %% When analysing, the data from the local ?COVER_TABLE is moved to the %% ?COLLECTION_TABLE. Resetting data in ?COVER_TABLE move_modules({Module,Clauses}) -> ets:insert(?COLLECTION_CLAUSE_TABLE,{Module,Clauses}), - move_clauses(Clauses). + Pattern = {#bump{module=Module, _='_'}, '_'}, + MatchSpec = [{Pattern,[],['$_']}], + Match = ets:select(?COVER_TABLE,MatchSpec,?CHUNK_SIZE), + do_move_module(Match). -move_clauses([{M,F,A,C,_L}|Clauses]) -> - Pattern = {#bump{module=M, function=F, arity=A, clause=C}, '_'}, - Bumps = ets:match_object(?COVER_TABLE,Pattern), +do_move_module({Bumps,Continuation}) -> lists:foreach(fun({Key,Val}) -> ets:insert(?COVER_TABLE, {Key,0}), insert_in_collection_table(Key,Val) end, Bumps), - move_clauses(Clauses); -move_clauses([]) -> + do_move_module(ets:select(Continuation)); +do_move_module('$end_of_table') -> ok. %% Given a .beam file, find the .erl file. Look first in same directory as @@ -1962,7 +2160,13 @@ find_source(Module, File0) -> throw_file(filename:join([BeamDir, "..", "src", Base])), %% Not in ../src: look for source path in compile info, but %% first look relative the beam directory. - Info = lists:keyfind(source, 1, Module:module_info(compile)), + Info = + try lists:keyfind(source, 1, Module:module_info(compile)) + catch error:undef -> + %% The module might have been imported + %% and the beam not available + throw({beam, File0}) + end, false == Info andalso throw({beam, File0}), %% stripped {source, SrcFile} = Info, throw_file(splice(BeamDir, SrcFile)), %% below ../src @@ -2002,6 +2206,26 @@ splice(BeamDir, SrcFile) -> revsplit(Path) -> lists:reverse(filename:split(Path)). +analyse_list(Modules, Analysis, Level, State) -> + {LoadedMF, ImportedMF, Error} = are_loaded(Modules, State, [], [], []), + Loaded = [M || {M,_} <- LoadedMF], + Imported = [M || {M,_} <- ImportedMF], + collect(Loaded, State#main_state.nodes), + MS = [{{'$1','_'},[{'==','$1',M}],['$_']} || M <- Loaded ++ Imported], + AllClauses = ets:select(?COLLECTION_CLAUSE_TABLE,MS), + Fun = fun({Module,Clauses}) -> + do_analyse(Module, Analysis, Level, Clauses) + end, + {result, lists:flatten(pmap(Fun, AllClauses)), Error}. + +analyse_all(Analysis, Level, State) -> + collect(State#main_state.nodes), + AllClauses = ets:tab2list(?COLLECTION_CLAUSE_TABLE), + Fun = fun({Module,Clauses}) -> + do_analyse(Module, Analysis, Level, Clauses) + end, + {result, lists:flatten(pmap(Fun, AllClauses)), []}. + do_parallel_analysis(Module, Analysis, Level, Loaded, From, State) -> analyse_info(Module,State#main_state.imported), C = case Loaded of @@ -2016,7 +2240,7 @@ do_parallel_analysis(Module, Analysis, Level, Loaded, From, State) -> Clauses end, R = do_analyse(Module, Analysis, Level, C), - reply(From, R). + reply(From, {ok,R}). %% do_analyse(Module, Analysis, Level, Clauses)-> {ok,Answer} | {error,Error} %% Clauses = [{Module,Function,Arity,Clause,Lines}] @@ -2035,37 +2259,44 @@ do_analyse(Module, Analysis, line, _Clauses) -> {{Module,L}, N} end end, - Answer = lists:keysort(1, lists:map(Fun, Bumps)), - {ok, Answer}; -do_analyse(_Module, Analysis, clause, Clauses) -> - Fun = case Analysis of - coverage -> - fun({M,F,A,C,Ls}) -> - Pattern = {#bump{module=M,function=F,arity=A, - clause=C},0}, - Bumps = ets:match_object(?COLLECTION_TABLE, Pattern), - NotCov = length(Bumps), - {{M,F,A,C}, {Ls-NotCov, NotCov}} - end; - calls -> - fun({M,F,A,C,_Ls}) -> - Pattern = {#bump{module=M,function=F,arity=A, - clause=C},'_'}, - Bumps = ets:match_object(?COLLECTION_TABLE, Pattern), - {_Bump, Calls} = hd(lists:keysort(1, Bumps)), - {{M,F,A,C}, Calls} - end - end, - Answer = lists:map(Fun, Clauses), - {ok, Answer}; + lists:keysort(1, lists:map(Fun, Bumps)); +do_analyse(Module, Analysis, clause, _Clauses) -> + Pattern = {#bump{module=Module},'_'}, + Bumps = lists:keysort(1,ets:match_object(?COLLECTION_TABLE, Pattern)), + analyse_clause(Analysis,Bumps); do_analyse(Module, Analysis, function, Clauses) -> - {ok, ClauseResult} = do_analyse(Module, Analysis, clause, Clauses), - Result = merge_clauses(ClauseResult, merge_fun(Analysis)), - {ok, Result}; + ClauseResult = do_analyse(Module, Analysis, clause, Clauses), + merge_clauses(ClauseResult, merge_fun(Analysis)); do_analyse(Module, Analysis, module, Clauses) -> - {ok, FunctionResult} = do_analyse(Module, Analysis, function, Clauses), + FunctionResult = do_analyse(Module, Analysis, function, Clauses), Result = merge_functions(FunctionResult, merge_fun(Analysis)), - {ok, {Module,Result}}. + {Module,Result}. + +analyse_clause(_,[]) -> + []; +analyse_clause(coverage, + [{#bump{module=M,function=F,arity=A,clause=C},_}|_]=Bumps) -> + analyse_clause_cov(Bumps,{M,F,A,C},0,0,[]); +analyse_clause(calls,Bumps) -> + analyse_clause_calls(Bumps,{x,x,x,x},[]). + +analyse_clause_cov([{#bump{module=M,function=F,arity=A,clause=C},N}|Bumps], + {M,F,A,C}=Clause,Ls,NotCov,Acc) -> + analyse_clause_cov(Bumps,Clause,Ls+1,if N==0->NotCov+1; true->NotCov end,Acc); +analyse_clause_cov([{#bump{module=M1,function=F1,arity=A1,clause=C1},_}|_]=Bumps, + Clause,Ls,NotCov,Acc) -> + analyse_clause_cov(Bumps,{M1,F1,A1,C1},0,0,[{Clause,{Ls-NotCov,NotCov}}|Acc]); +analyse_clause_cov([],Clause,Ls,NotCov,Acc) -> + lists:reverse(Acc,[{Clause,{Ls-NotCov,NotCov}}]). + +analyse_clause_calls([{#bump{module=M,function=F,arity=A,clause=C},_}|Bumps], + {M,F,A,C}=Clause,Acc) -> + analyse_clause_calls(Bumps,Clause,Acc); +analyse_clause_calls([{#bump{module=M1,function=F1,arity=A1,clause=C1},N}|Bumps], + _Clause,Acc) -> + analyse_clause_calls(Bumps,{M1,F1,A1,C1},[{{M1,F1,A1,C1},N}|Acc]); +analyse_clause_calls([],_Clause,Acc) -> + lists:reverse(Acc). merge_fun(coverage) -> fun({Cov1,NotCov1}, {Cov2,NotCov2}) -> @@ -2094,7 +2325,50 @@ merge_functions([{_MFA,R}|Functions], MFun, Result) -> merge_functions([], _MFun, Result) -> Result. -do_parallel_analysis_to_file(Module, OutFile, Opts, Loaded, From, State) -> +analyse_list_to_file(Modules, Opts, State) -> + {LoadedMF, ImportedMF, Error} = are_loaded(Modules, State, [], [], []), + collect([M || {M,_} <- LoadedMF], State#main_state.nodes), + OutDir = proplists:get_value(outdir,Opts), + HTML = lists:member(html,Opts), + Fun = fun({Module,File}) -> + OutFile = outfilename(OutDir,Module,HTML), + do_analyse_to_file(Module,File,OutFile,HTML,State) + end, + {Ok,Error1} = split_ok_error(pmap(Fun, LoadedMF++ImportedMF),[],[]), + {result,Ok,Error ++ Error1}. + +analyse_all_to_file(Opts, State) -> + collect(State#main_state.nodes), + AllModules = get_all_modules(State), + OutDir = proplists:get_value(outdir,Opts), + HTML = lists:member(html,Opts), + Fun = fun({Module,File}) -> + OutFile = outfilename(OutDir,Module,HTML), + do_analyse_to_file(Module,File,OutFile,HTML,State) + end, + {Ok,Error} = split_ok_error(pmap(Fun, AllModules),[],[]), + {result,Ok,Error}. + +get_all_modules(State) -> + get_all_modules(State#main_state.compiled ++ State#main_state.imported,[]). +get_all_modules([{Module,File}|Rest],Acc) -> + get_all_modules(Rest,[{Module,File}|Acc]); +get_all_modules([{Module,File,_}|Rest],Acc) -> + case lists:keymember(Module,1,Acc) of + true -> get_all_modules(Rest,Acc); + false -> get_all_modules(Rest,[{Module,File}|Acc]) + end; +get_all_modules([],Acc) -> + Acc. + +split_ok_error([{ok,R}|Result],Ok,Error) -> + split_ok_error(Result,[R|Ok],Error); +split_ok_error([{error,R}|Result],Ok,Error) -> + split_ok_error(Result,Ok,[R|Error]); +split_ok_error([],Ok,Error) -> + {Ok,Error}. + +do_parallel_analysis_to_file(Module, Opts, Loaded, From, State) -> File = case Loaded of {loaded, File0} -> [{Module,Clauses}] = @@ -2105,24 +2379,32 @@ do_parallel_analysis_to_file(Module, OutFile, Opts, Loaded, From, State) -> {imported, File0, _} -> File0 end, + HTML = lists:member(html,Opts), + OutFile = + case proplists:get_value(outfile,Opts) of + undefined -> + outfilename(proplists:get_value(outdir,Opts),Module,HTML); + F -> + F + end, + reply(From, do_analyse_to_file(Module,File,OutFile,HTML,State)). + +do_analyse_to_file(Module,File,OutFile,HTML,State) -> case find_source(Module, File) of {beam,_BeamFile} -> - reply(From, {error,no_source_code_found}); + {error,{no_source_code_found,Module}}; ErlFile -> analyse_info(Module,State#main_state.imported), - HTML = lists:member(html,Opts), - R = do_analyse_to_file(Module,OutFile, - ErlFile,HTML), - reply(From, R) + do_analyse_to_file1(Module,OutFile,ErlFile,HTML) end. -%% do_analyse_to_file(Module,OutFile,ErlFile) -> {ok,OutFile} | {error,Error} +%% do_analyse_to_file1(Module,OutFile,ErlFile) -> {ok,OutFile} | {error,Error} %% Module = atom() %% OutFile = ErlFile = string() -do_analyse_to_file(Module, OutFile, ErlFile, HTML) -> - case file:open(ErlFile, [read]) of +do_analyse_to_file1(Module, OutFile, ErlFile, HTML) -> + case file:open(ErlFile, [read,raw,read_ahead]) of {ok, InFd} -> - case file:open(OutFile, [write]) of + case file:open(OutFile, [write,raw,delayed_write]) of {ok, OutFd} -> if HTML -> Encoding = encoding(ErlFile), @@ -2160,9 +2442,14 @@ do_analyse_to_file(Module, OutFile, ErlFile, HTML) -> "**************************************" "\n\n"]), - print_lines(Module, InFd, OutFd, 1, HTML), + Pattern = {#bump{module=Module,line='$1',_='_'},'$2'}, + MS = [{Pattern,[{is_integer,'$1'},{'>','$1',0}],[{{'$1','$2'}}]}], + CovLines = lists:keysort(1,ets:select(?COLLECTION_TABLE, MS)), + print_lines(Module, CovLines, InFd, OutFd, 1, HTML), - if HTML -> io:format(OutFd,"</pre>\n</body>\n</html>\n",[]); + if + HTML -> + file:write(OutFd, "</pre>\n</body>\n</html>\n"); true -> ok end, @@ -2179,21 +2466,19 @@ do_analyse_to_file(Module, OutFile, ErlFile, HTML) -> {error, {file, ErlFile, Reason}} end. -print_lines(Module, InFd, OutFd, L, HTML) -> - case io:get_line(InFd, '') of + +print_lines(Module, CovLines, InFd, OutFd, L, HTML) -> + case file:read_line(InFd) of eof -> ignore; - "%"++_=Line -> %Comment line - not executed. - io:put_chars(OutFd, [tab(),escape_lt_and_gt(Line, HTML)]), - print_lines(Module, InFd, OutFd, L+1, HTML); - RawLine -> + {ok,"%"++_=Line} -> %Comment line - not executed. + file:write(OutFd, [tab(),escape_lt_and_gt(Line, HTML)]), + print_lines(Module, CovLines, InFd, OutFd, L+1, HTML); + {ok,RawLine} -> Line = escape_lt_and_gt(RawLine,HTML), - Pattern = {#bump{module=Module,line=L},'$1'}, - case ets:match(?COLLECTION_TABLE, Pattern) of - [] -> - io:put_chars(OutFd, [tab(),Line]); - Ns -> - N = lists:foldl(fun([Ni], Nacc) -> Nacc+Ni end, 0, Ns), + case CovLines of + [{L,N}|CovLines1] -> + %% N = lists:foldl(fun([Ni], Nacc) -> Nacc+Ni end, 0, Ns), if N=:=0, HTML=:=true -> LineNoNL = Line -- "\n", @@ -2201,19 +2486,22 @@ print_lines(Module, InFd, OutFd, L, HTML) -> %%Str = string:right("0", 6, 32), RedLine = ["<font color=red>",Str,fill1(), LineNoNL,"</font>\n"], - io:put_chars(OutFd, RedLine); + file:write(OutFd, RedLine); N<1000000 -> Str = string:right(integer_to_list(N), 6, 32), - io:put_chars(OutFd, [Str,fill1(),Line]); + file:write(OutFd, [Str,fill1(),Line]); N<10000000 -> Str = integer_to_list(N), - io:put_chars(OutFd, [Str,fill2(),Line]); + file:write(OutFd, [Str,fill2(),Line]); true -> Str = integer_to_list(N), - io:put_chars(OutFd, [Str,fill3(),Line]) - end - end, - print_lines(Module, InFd, OutFd, L+1, HTML) + file:write(OutFd, [Str,fill3(),Line]) + end, + print_lines(Module, CovLines1, InFd, OutFd, L+1, HTML); + _ -> + file:write(OutFd, [tab(),Line]), + print_lines(Module, CovLines, InFd, OutFd, L+1, HTML) + end end. tab() -> " | ". @@ -2223,7 +2511,7 @@ fill3() -> "| ". %%%--Export-------------------------------------------------------------- do_export(Module, OutFile, From, State) -> - case file:open(OutFile,[write,binary,raw]) of + case file:open(OutFile,[write,binary,raw,delayed_write]) of {ok,Fd} -> Reply = case Module of @@ -2362,21 +2650,21 @@ do_reset_collection_table(Module) -> ets:match_delete(?COLLECTION_TABLE, {#bump{module=Module},'_'}). %% do_reset(Module) -> ok -%% The reset is done on a per-clause basis to avoid building +%% The reset is done on ?CHUNK_SIZE number of bumps to avoid building %% long lists in the case of very large modules do_reset(Module) -> - [{Module,Clauses}] = ets:lookup(?COVER_CLAUSE_TABLE, Module), - do_reset2(Clauses). + Pattern = {#bump{module=Module, _='_'}, '$1'}, + MatchSpec = [{Pattern,[{'=/=','$1',0}],['$_']}], + Match = ets:select(?COVER_TABLE,MatchSpec,?CHUNK_SIZE), + do_reset2(Match). -do_reset2([{M,F,A,C,_L}|Clauses]) -> - Pattern = {#bump{module=M, function=F, arity=A, clause=C}, '_'}, - Bumps = ets:match_object(?COVER_TABLE, Pattern), +do_reset2({Bumps,Continuation}) -> lists:foreach(fun({Bump,_N}) -> ets:insert(?COVER_TABLE, {Bump,0}) end, Bumps), - do_reset2(Clauses); -do_reset2([]) -> + do_reset2(ets:select(Continuation)); +do_reset2('$end_of_table') -> ok. do_clear(Module) -> @@ -2419,31 +2707,43 @@ escape_lt_and_gt1([],Acc) -> escape_lt_and_gt1([H|T],Acc) -> escape_lt_and_gt1(T,[H|Acc]). -pmap(Fun, List) -> - pmap(Fun, List, 20). -pmap(Fun, List, Limit) -> - pmap(Fun, List, [], Limit, 0, []). -pmap(Fun, [E | Rest], Pids, Limit, Cnt, Acc) when Cnt < Limit -> - Collector = self(), - Pid = spawn_link(fun() -> - ?SPAWN_DBG(pmap,E), - Collector ! {res,self(),Fun(E)} - end), - erlang:monitor(process, Pid), - pmap(Fun, Rest, Pids ++ [Pid], Limit, Cnt + 1, Acc); -pmap(Fun, List, [Pid | Pids], Limit, Cnt, Acc) -> - receive - {'DOWN', _Ref, process, X, _} when is_pid(X) -> - pmap(Fun, List, [Pid | Pids], Limit, Cnt - 1, Acc); - {res, Pid, Res} -> - pmap(Fun, List, Pids, Limit, Cnt, [Res | Acc]) - end; -pmap(_Fun, [], [], _Limit, 0, Acc) -> - lists:reverse(Acc); -pmap(Fun, [], [], Limit, Cnt, Acc) -> +%%%--Internal functions for parallelization------------------------------ +pmap(Fun,List) -> + NTot = length(List), + NProcs = erlang:system_info(schedulers) * 2, + NPerProc = (NTot div NProcs) + 1, + Mons = pmap_spawn(Fun,NPerProc,List,[]), + pmap_collect(Mons,[]). + +pmap_spawn(_,_,[],Mons) -> + Mons; +pmap_spawn(Fun,NPerProc,List,Mons) -> + {L1,L2} = if length(List)>=NPerProc -> lists:split(NPerProc,List); + true -> {List,[]} % last chunk + end, + Mon = + spawn_monitor( + fun() -> + exit({pmap_done,lists:map(Fun,L1)}) + end), + pmap_spawn(Fun,NPerProc,L2,[Mon|Mons]). + +pmap_collect([],Acc) -> + lists:append(Acc); +pmap_collect(Mons,Acc) -> receive - {'DOWN', _Ref, process, X, _} when is_pid(X) -> - pmap(Fun, [], [], Limit, Cnt - 1, Acc) + {'DOWN', Ref, process, Pid, {pmap_done,Result}} -> + pmap_collect(lists:delete({Pid,Ref},Mons),[Result|Acc]); + {'DOWN', Ref, process, Pid, Reason} = Down -> + case lists:member({Pid,Ref},Mons) of + true -> + %% Something went really wrong - don't hang! + exit(Reason); + false -> + %% This should be handled somewhere else + self() ! Down, + pmap_collect(Mons,Acc) + end end. %%%----------------------------------------------------------------- diff --git a/lib/tools/src/cover_web.erl b/lib/tools/src/cover_web.erl deleted file mode 100644 index 69f2f3b1aa..0000000000 --- a/lib/tools/src/cover_web.erl +++ /dev/null @@ -1,1184 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% - --module(cover_web). --author('[email protected]'). --behaviour(gen_server). - -%%Export of configuration function --export([configData/0]). -%% External exports --export([init/1, handle_call/3, handle_cast/2, handle_info/2, - terminate/2, code_change/3]). - --export([start_link/0,start/0,stop/0]). --export([menu_frame/2,nodes_frame/2,import_frame/2, - compile_frame/2,result_frame/2]). --export([list_dir/2,compile/2,add_node/2,remove_node/2,result/2, - calls/2,coverage/2,import/2]). - --record(state,{dir}). - --include_lib("kernel/include/file.hrl"). - -%% Timeouts --define(DEFAULT_TIME,10000). --define(MAX_COMPILE_TIME,60000). --define(MAX_ANALYSE_TIME,30000). - -%% Colors --define(INFO_BG_COLOR,"#C0C0EA"). - -%%%---------------------------------------------------------------------- -%%% API - called from erlang shell -%%%---------------------------------------------------------------------- -%% Start webtool and webcover from erlang shell -start() -> - webtool:start(), - webtool:start_tools([],"app=webcover"), - ok. - -%% Stop webtool and webcover from erlang shell -stop() -> - webtool:stop_tools([],"app=webcover"), - webtool:stop(). - - - -%%%---------------------------------------------------------------------- -%%% API - called from webtool -%%%---------------------------------------------------------------------- -start_link() -> - gen_server:start_link({local, webcover_server},cover_web, [], []). - - -nodes_frame(Env,Input)-> - call({nodes_frame,Env,Input}). - -add_node(Env,Input)-> - call({add_node,Env,Input}). - -remove_node(Env,Input)-> - call({remove_node,Env,Input}). - -compile_frame(Env,Input)-> - call({compile_frame,Env,Input}). - -list_dir(Env,Input) -> - call({list_dir,Env,Input}). - -compile(Env,Input)-> - call({compile,Env,Input},?MAX_COMPILE_TIME). - -result_frame(Env,Input)-> - call({result_frame,Env,Input}). - -result(Env,Input) -> - call({result,Env,Input},?MAX_ANALYSE_TIME). - -calls(Env,Input) -> - call({calls,Env,Input}). - -coverage(Env,Input) -> - call({coverage,Env,Input}). - -import_frame(Env,Input)-> - call({import_frame,Env,Input}). - -import(Env,Input)-> - call({import,Env,Input}). - -menu_frame(Env,Input)-> - call({menu_frame,Env,Input}). - -call(Msg) -> - call(Msg,?DEFAULT_TIME). -call(Msg,Time) -> - gen_server:call(webcover_server,Msg,Time). - - - -configData()-> - {webcover,[{web_data,{"WebCover","/webcover"}}, - {alias,{"/webcover",code:priv_dir(tools)}}, - {alias,{erl_alias,"/webcover/erl",[cover_web]}}, - {start,{child,{{local,webcover_server}, - {cover_web,start_link,[]}, - permanent,100,worker,[cover_web]}}} - ]}. - - -%%%---------------------------------------------------------------------- -%%% Callback functions from gen_server -%%%---------------------------------------------------------------------- - -%%---------------------------------------------------------------------- -%% Func: init/1 -%% Returns: {ok, State} | -%% {ok, State, Timeout} | -%% ignore | -%% {stop, Reason} -%%---------------------------------------------------------------------- -init([]) -> - cover:start(), - CS = whereis(cover_server), - link(CS), - GL = spawn_link(fun group_leader_proc/0), - group_leader(GL,CS), - - %% Must trap exists in order to have terminate/2 executed when - %% crashing because of a linked process crash. - process_flag(trap_exit,true), - {ok,Cwd} = file:get_cwd(), - {ok, #state{dir=Cwd}}. - -group_leader_proc() -> - register(cover_group_leader_proc,self()), - group_leader_loop([]). -group_leader_loop(Warnings) -> - receive - {io_request,From,ReplyAs,{put_chars,io_lib,Func,[Format,Args]}} -> - Msg = (catch io_lib:Func(Format,Args)), - From ! {io_reply,ReplyAs,ok}, - case lists:member(Msg,Warnings) of - true -> group_leader_loop(Warnings); - false -> group_leader_loop([Msg|Warnings]) - end; - {io_request,From,ReplyAs,{put_chars,_Encoding,io_lib,Func,[Format,Args]}} -> - Msg = (catch io_lib:Func(Format,Args)), - From ! {io_reply,ReplyAs,ok}, - case lists:member(Msg,Warnings) of - true -> group_leader_loop(Warnings); - false -> group_leader_loop([Msg|Warnings]) - end; - IoReq when element(1,IoReq)=:= io_request -> - group_leader() ! IoReq, - group_leader_loop(Warnings); - {From,get_warnings} -> - Warnings1 = - receive - {io_request,From,ReplyAs, - {put_chars,io_lib,Func,[Format,Args]}} -> - Msg = (catch io_lib:Func(Format,Args)), - From ! {io_reply,ReplyAs,ok}, - case lists:member(Msg,Warnings) of - true -> Warnings; - false -> [Msg|Warnings] - end - after 0 -> - Warnings - end, - From ! {warnings,Warnings1}, - group_leader_loop([]) - end. - -%%---------------------------------------------------------------------- -%% Func: handle_call/3 -%% Returns: {reply, Reply, State} | -%% {reply, Reply, State, Timeout} | -%% {noreply, State} | -%% {noreply, State, Timeout} | -%% {stop, Reason, Reply, State} | (terminate/2 is called) -%% {stop, Reason, State} (terminate/2 is called) -%%---------------------------------------------------------------------- -handle_call({nodes_frame,_Env,_Input},_From,State)-> - {reply,nodes_frame1(),State}; - -handle_call({add_node,_Env,Input},_From,State)-> - {reply,do_add_node(Input),State}; - -handle_call({remove_node,_Env,Input},_From,State)-> - {reply,do_remove_node(Input),State}; - -handle_call({compile_frame,_Env,_Input},_From,State)-> - {reply,compile_frame1(State#state.dir),State}; - -handle_call({list_dir,_Env,Input},_From,State)-> - Dir = get_input_data(Input,"path"), - case filelib:is_dir(Dir) of - true -> - {reply,compile_frame1(Dir),State#state{dir=Dir}}; - false -> - Err = Dir ++ " is not a directory", - {reply,compile_frame1(State#state.dir,Err),State} - end; -handle_call({compile,_Env,Input},_From,State)-> - {reply,do_compile(Input,State#state.dir),State}; - -handle_call({result_frame,_Env,_Input},_From,State)-> - {reply,result_frame1(),State}; - -handle_call({result,_Env,Input},_From,State)-> - {reply,handle_result(Input),State}; - -handle_call({calls,_Env,Input},_From,State)-> - {reply,call_page(Input),State}; - -handle_call({coverage,_Env,Input},_From,State)-> - {reply,coverage_page(Input),State}; - -handle_call({import_frame,_Env,_Input},_From,State)-> - {ok,Cwd} = file:get_cwd(), - {reply,import_frame1(Cwd),State}; - -handle_call({import,_Env,Input},_From,State)-> - {reply,do_import(Input),State}; - -handle_call({menu_frame,_Env,_Input},_From,State)-> - {reply,menu_frame1(),State}; - -handle_call(_Request, _From, State) -> - Reply = bad_request, - {reply, Reply, State}. - - -%%---------------------------------------------------------------------- -%% Func: handle_cast/2 -%% Returns: {noreply, State} | -%% {noreply, State, Timeout} | -%% {stop, Reason, State} (terminate/2 is called) -%%---------------------------------------------------------------------- -handle_cast(_Msg, State) -> - {noreply, State}. - -%%---------------------------------------------------------------------- -%% Func: handle_info/2 -%% Returns: {noreply, State} | -%% {noreply, State, Timeout} | -%% {stop, Reason, State} (terminate/2 is called) -%%---------------------------------------------------------------------- -handle_info({'EXIT',_Pid,Reason}, State) -> - {stop, Reason, State}. - -%%---------------------------------------------------------------------- -%% Func: terminate/2 -%% Purpose: Shutdown the server -%% Returns: any (ignored by gen_server) -%%---------------------------------------------------------------------- -terminate(_Reason, _State) -> - cover:stop(), - ok. - -%%-------------------------------------------------------------------- -%% Func: code_change/3 -%% Purpose: Convert process state when code is changed -%% Returns: {ok, NewState} -%%-------------------------------------------------------------------- -code_change(_OldVsn, State, _Extra) -> - {ok, State}. - -%%%---------------------------------------------------------------------- -%%% Internal functions -%%%---------------------------------------------------------------------- - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% %% -%% The functions that creates the whole pages by collecting all the %% -%% neccessary data for each page. These functions are the public %% -%% interface. %% -%% %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%---------------------------------------------------------------------- -%% Returns the page to the left frame -%%---------------------------------------------------------------------- -menu_frame1()-> - [header(),html_header(""),menu_body(),html_end()]. - -%%---------------------------------------------------------------------- -%% Creates the page where the user can add and remove nodes -%%---------------------------------------------------------------------- - -nodes_frame1()-> - nodes_frame1([]). -nodes_frame1(Err)-> - [header(),html_header("Add/remove nodes"),nodes_body(Err),html_end()]. - -%%---------------------------------------------------------------------- -%% Creates the page where the user can cover compile modules -%%---------------------------------------------------------------------- - -compile_frame1(Dir)-> - compile_frame1(Dir,[]). -compile_frame1(Dir,Err) -> - [header(),html_header("Cover compile"),compile_body(Dir,Err),html_end()]. - -%%---------------------------------------------------------------------- -%% Creates the page where the user can handle results -%%---------------------------------------------------------------------- - -result_frame1()-> - result_frame1([]). -result_frame1(Err) -> - [header(),html_header("Show cover results"),result_body(Err),html_end()]. - -%%---------------------------------------------------------------------- -%%The beginning of the page that clear the cover information on a cover -%%compiled module -%%---------------------------------------------------------------------- -call_page(Input)-> - [header(),html_header("Code coverage"),call_result(Input),html_end()]. - -coverage_page(Input)-> - [header(),html_header("Code coverage"),coverage_result(Input),html_end()]. - -%%---------------------------------------------------------------------- -%% Creates the page where the user an import files -%%---------------------------------------------------------------------- -import_frame1(Dir) -> - import_frame1(Dir,""). -import_frame1(Dir,Err) -> - [header(),html_header("Import coverdata"),import_body(Dir,Err),html_end()]. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% %% -%% The functions that build the body of the menu frame %% -%% %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -menu_body() -> - Nodes = cover:which_nodes(), - Modules = cover:modules(), - Imported = cover:imported(), - ["<A HREF=\"./nodes_frame\" TARGET=\"main\">Nodes</A><BR>\n", - "<A HREF=\"./compile_frame\" TARGET=\"main\">Compile</A><BR>\n", - "<A HREF=\"./import_frame\" TARGET=\"main\">Import</A><BR>\n", - "<A HREF=\"./result_frame\" TARGET=\"main\">Result</A>\n", - "<P><B>Nodes:</B>\n", - "<UL>\n", - lists:map(fun(N) -> "<LI>"++atom_to_list(N)++"</LI>\n" end,[node()|Nodes]), - "</UL>\n", - "<P><B>Compiled modules:</B>\n", - "<UL>\n", - lists:map(fun(M) -> "<LI>"++atom_to_list(M)++"</LI>\n" end,Modules), - "</UL>\n", - "<P><B>Imported files:</B>\n", - "<UL>\n", - "<FONT SIZE=-1>\n", - lists:map(fun(F) -> - Short = filename:basename(F), - "<LI TITLE=\""++F++"\">"++Short++"</LI>\n" end,Imported), - "</FONT>\n", - "</UL>\n"]. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% %% -%% The functions that build the body of the nodes frame %% -%% %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -nodes_body(Err) -> - CN = cover:which_nodes(), - Fun = fun(N) -> - NStr = atom_to_list(N), - ["<OPTION VALUE=",NStr, - " onClick=\"node.value=selected_node.value\">",NStr, - "</OPTION>\n"] - end, - AllNodes = lists:append(lists:map(Fun,nodes()--CN)), - CoverNodes = lists:append(lists:map(Fun,CN)), - - [reload_menu_script(Err), - "<H1 ALIGN=center>Nodes</H1>\n", - "<TABLE BORDER=0 WIDTH=600 ALIGN=center>\n", - "<TR><TD BGCOLOR=",?INFO_BG_COLOR," COLSPAN=2>\n", - "<P>You can run cover over several nodes simultaneously. Coverage data\n", - "from all involved nodes will be merged during analysis.\n", - "<P>Select or enter node names to add or remove here.\n", - "</TD></TR>\n", - "<TR><TD COLSPAN=2><BR><BR></TD></TR>\n", - "<FORM ACTION=\"./add_node\" NAME=add_node>\n", - "<TR><TD VALIGN=top>Add node:</TD>\n", - "<TD><INPUT TYPE=text NAME=\"node\" SIZE=40 >", - "<INPUT TYPE=submit\n", - " onClick=\"if(!node.value){node.value=selected_node.value};\" VALUE=Add>" - "<BR><SELECT NAME=selected_node TITLE=\"Select node\">\n", - AllNodes ++ - "</SELECT>\n", - "</TD></TR>\n" - "</FORM>\n", - "<TR><TD COLSPAN=2><BR><BR></TD></TR>\n", - "<FORM ACTION=\"./remove_node\" NAME=remove_node>\n", - "<TR><TD>Remove node:</TD>\n", - "<TD><SELECT NAME=node TITLE=\"Select node\">\n", - CoverNodes ++ - "</SELECT>\n", - "<INPUT TYPE=submit VALUE=Remove>" - "</TD></TR>\n", - "</FORM>", - "</TABLE>"]. - - -do_add_node(Input) -> - NodeStr = get_input_data(Input, "node"), - Node = list_to_atom(NodeStr), - case net_adm:ping(Node) of - pong -> - cover:start(Node), - nodes_frame1(); - pang -> - nodes_frame1("Node \\\'" ++ NodeStr ++ "\\\' is not alive") - end. - -do_remove_node(Input) -> - Node = list_to_atom(get_input_data(Input, "node")), - cover:stop(Node), - nodes_frame1(). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% The functions that is used when the user wants to compile something % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -compile_body(Dir,Err) -> - Erls = filelib:wildcard(filename:join(Dir,"*.erl")), - Beams = filelib:wildcard(filename:join(Dir,"*.beam")), - - [reload_menu_script(Err), - "<H1 ALIGN=center>Compile</H1>\n", - "<TABLE WIDTH=600 ALIGN=center BORDER=0>\n", - "<TR><TD COLSPAN=3 BGCOLOR=",?INFO_BG_COLOR,">\n", - "Each module which shall be part of the cover analysis must be prepared\n", - "or 'cover compiled'. On this page you can select .erl files and/or\n", - ".beam files to include in the analysis. If you select a .erl file it\n", - "will first be compiled with the Erlang compiler and then prepared for\n", - "coverage analysis. If you select a .beam file it will be prepared for\n", - "coverage analysis directly.\n", - "</TD></TR>\n", - "<FORM ACTION=\"./list_dir\" NAME=list_dir>\n", - "<TR><TD WIDTH=30% BGCOLOR=",?INFO_BG_COLOR," ROWSPAN=2>\n", - "To list a different directory, enter the directory name here.\n", - "</TD>\n", - "<TH COLSPAN=2><BR>List directory:<BR></TH>\n", - "</TR>\n", - "<TR><TD ALIGN=center COLSPAN=2>\n", - "<INPUT TYPE=text NAME=\"path\" SIZE=40 VALUE=",Dir,">", - "<INPUT TYPE=submit VALUE=Ok>", - "<BR><BR></TD></TR>\n", - "</FORM>\n", - "<FORM ACTION=\"./compile\" NAME=compile_selection>\n", - "<TR><TD BGCOLOR=",?INFO_BG_COLOR," ROWSPAN=2>\n", - "<P>Select one or more .erl or .beam files to prepare for coverage\n" - "analysis, and click the \"Compile\" button.\n", - "<P>To reload the original file after coverage analysis is complete,\n" - "select one or more files and click the \"Uncompile\" button, or\n", - "simply click the \"Uncompile all\" button to reload all originals.\n" - "</TD>\n", - "<TH>.erl files</TH><TH>.beam files</TH></TR>\n", - "<TR><TD ALIGN=center VALIGN=top>\n", - "<SELECT NAME=erl TITLE=\"Select .erl files to compile\" MULTIPLE=true", - " SIZE=15>\n", - list_modules(Erls) ++ - "</SELECT></TD>\n", - "<TD ALIGN=center VALIGN=top>\n", - "<SELECT NAME=beam TITLE=\"Select .beam files to compile\"MULTIPLE=true", - " SIZE=15>\n", - list_modules(Beams) ++ - "</SELECT></TD></TR>\n" - "<TR><TD BGCOLOR=",?INFO_BG_COLOR," ROWSPAN=2>\n", - "Compile options are only needed for .erl files. The options must be\n" - "given e.g. like this: \n" - "<FONT SIZE=-1>[{i,\"/my/path/include\"},{i,\"/other/path/\"}]</FONT>\n" - "</TD>\n", - "<TH COLSPAN=2><BR>Compile options:<BR></TH>\n", - "</TR>\n", - "<TR><TD COLSPAN=2 ALIGN=center>\n", - "<INPUT TYPE=text NAME=\"options\" SIZE=40>\n", - "<INPUT TYPE=hidden NAME=\"action\"></TD></TR>\n", - "<TR><TD></TD><TD ALIGN=center COLSPAN=2>\n", - "<INPUT TYPE=submit onClick=\"action.value=\'compile\';\"VALUE=Compile>", - "<INPUT TYPE=submit onClick=\"action.value=\'uncompile\';\" ", - "VALUE=Uncompile>", - "<INPUT TYPE=submit onClick=\"action.value=\'uncompile_all\';\" ", - "VALUE=\"Uncompile all\">", - "<BR><INPUT TYPE=reset VALUE=\"Reset form\"></TD></TR>\n", - "</FORM>\n", - "</TABLE>\n"]. - -list_modules([File|Files]) -> - Mod = filename:basename(File), - ["<OPTION VALUE=",File," onDblClick=\"action.value=\'compile\';submit();\">", - Mod,"</OPTION>\n" | list_modules(Files)]; -list_modules([]) -> - []. - -do_compile(Input,Dir) -> - {Erls,Beams,Opts,Action} = get_compile_input(parse(Input),[],[]), - Errs = - case Action of - "compile" -> - do_compile(Erls,Beams,Opts,[]); - "uncompile" -> - do_uncompile(Erls++Beams); - "uncompile_all" -> - do_uncompile(cover:modules()) - end, - compile_frame1(Dir,Errs). - -get_compile_input([{"erl",File}|Input],Erl,Beam) -> - get_compile_input(Input,[File|Erl],Beam); -get_compile_input([{"beam",File}|Input],Erl,Beam) -> - get_compile_input(Input,Erl,[File|Beam]); -get_compile_input([{"options",Opts0},{"action",Action}],Erl,Beam) -> - Opts = parse_options(Opts0), - {Erl,Beam,Opts,Action}. - -do_compile([Erl|Erls],Beams,Opts,Errs) -> - case cover:compile_module(Erl,Opts) of - {ok,_} -> - do_compile(Erls,Beams,Opts,Errs); - {error,File} -> - do_compile(Erls,Beams,Opts,["\\n"++File|Errs]) - end; -do_compile([],[Beam|Beams],Opts,Errs) -> - case cover:compile_beam(Beam) of - {ok,_} -> - do_compile([],Beams,Opts,Errs); - {error,{no_abstract_code,File}} -> - do_compile([],Beams,Opts,["\\n"++File++" (no_abstract_code)"|Errs]) - end; -do_compile([],[],_,[]) -> - []; -do_compile([],[],_,Errs) -> - "Compilation failed for the following files:" ++ Errs. - -parse_options(Options)-> - case erl_scan:string(Options ++".") of - {ok,Tokens,_Line} -> - case erl_parse:parse_exprs(Tokens) of - {ok,X}-> - case lists:map(fun erl_parse:normalise/1, X) of - [List] when is_list(List) -> List; - List -> List - end; - _ -> - [] - end; - _ -> - [] - end. - - -do_uncompile(Files) -> - lists:foreach( - fun(File) -> - Module = - if is_atom(File) -> - File; - true -> - ModStr = filename:basename(filename:rootname(File)), - list_to_atom(ModStr) - end, - case code:which(Module) of - cover_compiled -> - code:purge(Module), - case code:load_file(Module) of - {module, Module} -> - ok; - {error, _Reason2} -> - code:delete(Module) - end; - _ -> - ok - end - end, - Files), - []. - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% The functions that builds the body of the page for coverage analysis% -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -result_body(Err) -> - [reload_menu_script(Err), - "<H1 ALIGN=center>Result</H1>\n", - "<TABLE BORDER=0 WIDTH=600 ALIGN=center>\n", - "<TR><TD BGCOLOR=",?INFO_BG_COLOR,">\n", - "<P>After executing all your tests you can view the result of the\n", - "coverage analysis here. For each module you can\n", - "<DL>\n", - "<DT><B>Analyse to file</B></DT>\n", - "<DD>The source code of the module is shown with the number of calls\n", - "to each line stated in the left margin. Lines which are never called\n", - "are colored red.</DD>\n", - "<DT><B>Analyse coverage</B></DT>\n", - "<DD>Show the number of covered and uncovered lines in the module.</DD>\n", - "<DT><B>Analyse calls</B></DT>\n", - "<DD>Show the number of calls in the module.</DD>\n", - "<DT><B>Reset module</B></DT>\n", - "<DD>Delete all coverage data for the module.</DD>\n", - "<DT><B>Export module</B></DT>\n", - "<DD>Write all coverage data for the module to a file. The data can\n", - "later be imported from the \"Import\" page.</DD>\n", - "</DL>\n", - "<P>You can also reset or export data for all modules with the\n", - "<B>Reset all</B> and <B>Export all</B> actions respectively. For these\n", - "two actions there is no need to select a module.\n", - "<P>Select module and action from the drop down menus below, and click\n", - "the \"Execute\" button.\n", - "</TD></TR>\n", - "<TR><TD><BR><BR>\n", - result_selections(), - "</TD></TR></TABLE>"]. - -result_selections() -> - ModList = filter_modlist(cover:modules()++cover:imported_modules(),[]), - - ["<FORM ACTION=\"./result\" NAME=result_selection>\n", - "<TABLE WIDTH=\"300\" BORDER=0 ALIGN=center>\n", - "<TR><TD ALIGN=left>\n", - "Module:\n", - "<BR><SELECT NAME=module TITLE=\"Select module\">\n", - ModList ++ - "</SELECT>\n", - "</TD>\n", - "<TD ALIGN=left>\n", - "Action:\n", - "<BR><SELECT NAME=action TITLE=\"Select action\">\n", - "<OPTION VALUE=\"analyse_to_file\">Analyse to file</OPTION>\n" - "<OPTION VALUE=\"coverage\">Analyse coverage</OPTION>\n" - "<OPTION VALUE=\"calls\">Analyse calls</OPTION>\n" - "<OPTION VALUE=\"reset\">Reset module</OPTION>\n" - "<OPTION VALUE=\"reset_all\">Reset all</OPTION>\n" - "<OPTION VALUE=\"export\">Export module</OPTION>\n" - "<OPTION VALUE=\"export_all\">Export all</OPTION>\n" - "</SELECT>\n", - "</TD>\n", - "<TD ALIGN=center VALIGN=bottom><INPUT TYPE=submit VALUE=Execute>\n" - "</TD></TR>\n" - "</TABLE>\n", - "</FORM>\n"]. - -filter_modlist([M|Ms],Already) -> - case lists:member(M,Already) of - true -> - filter_modlist(Ms,Already); - false -> - MStr = atom_to_list(M), - ["<OPTION VALUE=",MStr,">",MStr,"</OPTION>\n" | - filter_modlist(Ms,[M|Already])] - end; -filter_modlist([],_Already) -> - []. - - - -handle_result(Input) -> - case parse(Input) of - [{"module",M},{"action",A}] -> - case A of - "analyse_to_file" -> - case cover:analyse_to_file(list_to_atom(M),[html]) of - {ok,File} -> - case file:read_file(File) of - {ok,HTML}-> - file:delete(File), - [header(), - reload_menu_script(""), - binary_to_list(HTML)]; - _ -> - result_frame1("Can not read file" ++ File) - end; - {error,no_source_code_found} -> - result_frame1("No source code found for \\\'" ++ - M ++ "\\\'") - end; - "calls" -> - call_page(Input); - "coverage" -> - coverage_page(Input); - "reset" -> - cover:reset(list_to_atom(M)), - result_frame1("Coverage data for \\\'" ++ M ++ - "\\\' is now reset"); - "reset_all" -> - cover:reset(), - result_frame1("All coverage data is now reset"); - "export" -> - ExportFile = generate_filename(M), - cover:export(ExportFile,list_to_atom(M)), - result_frame1("Coverage data for \\\'" ++ M ++ - "\\\' is now exported to file \\\"" ++ - ExportFile ++ "\\\""); - "export_all" -> - ExportFile = generate_filename("COVER"), - cover:export(ExportFile), - result_frame1( - "All coverage data is now exported to file \\\"" ++ - ExportFile ++ "\\\"") - end; - [{"action",_A}] -> - result_frame1("No module is selected") - end. - -generate_filename(Prefix) -> - {ok,Cwd} = file:get_cwd(), - filename:join(Cwd,Prefix ++ "_" ++ ts() ++ ".coverdata"). - -ts() -> - {{Y,M,D},{H,Min,S}} = calendar:now_to_local_time(now()), - io_lib:format("~4.4.0w~2.2.0w~2.2.0w-~2.2.0w~2.2.0w~2.2.0w", - [Y,M,D,H,Min,S]). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% The functions that builds the body of the page that shows the calls % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -call_result(Input)-> - Mod = list_to_atom(get_input_data(Input, "module")), - case cover:analyse(Mod,calls) of - {error,_}-> - error_body(); - {ok,_} -> - call_result2(Mod,Input) - end. - -call_result2(Mod,Input)-> - Result = - case get_input_data(Input,"what") of - "mod" -> - call_result(mod,Mod); - "func" -> - call_result(func,Mod); - "clause" -> - call_result(clause,Mod); - _-> - call_result(all,Mod) - end, - result_choice("calls",Mod) ++ Result. - -result_choice(Level,Mod)-> - ModStr=atom_to_list(Mod), - [reload_menu_script(""), - "<TABLE WIDTH=100%><TR>\n", - "<TD><A HREF=./",Level,"?module=",ModStr,"&what=all>All Data</A></TD>\n", - "<TD><A HREF=./",Level,"?module=",ModStr,"&what=mod>Module</A></TD>\n", - "<TD><A HREF=./",Level,"?module=",ModStr,"&what=func>Function</A></TD>\n", - "<TD><A HREF=./",Level,"?module=",ModStr,"&what=clause>Clause</A></TD>\n", - "</TR></TABLE><BR>\n"]. - -call_result(Mode,Module)-> - Content = - case Mode of - mod-> - format_cover_call(cover:analyse(Module,calls,module),mod); - func-> - format_cover_call(cover:analyse(Module,calls,function),func); - clause-> - format_cover_call(cover:analyse(Module,calls,clause),clause); - _-> - format_cover_call(cover:analyse(Module,calls,module),mod) ++ - format_cover_call(cover:analyse(Module,calls,function),func)++ - format_cover_call(cover:analyse(Module,calls,clause),clause) - end, - getModDate(Module,date())++"<BR>"++ - "<TABLE WIDTH=\"100%\" BORDER=1>" - ++ Content ++"</TABLE>". - - -format_cover_call({error,_},_)-> - ["<TR><TD>\n", - "<BR><BR><BR><BR>\n", - "<FONT SIZE=5>The selected module is not Cover Compiled</FONT>\n", - "<BR>\n", - "</TD></TR>\n"]; - -format_cover_call({ok,{Mod,Calls}},mod)-> - ["<TR BGCOLOR=\"#8899AA\"><TD COLSPAN=5><B>Module calls</B></TD></TR>\n", - "<TR><TD COLSPAN=4><I>Module</I></TD>", - "<TD ALIGN=\"right\"><I>Number of calls</I></TD></TR>\n", - "<TR><TD COLSPAN=4>" ++ atom_to_list(Mod) ++"</TD>" - "<TD ALIGN=\"right\">" ++ integer_to_list(Calls)++"</TD></TR>\n"]; - -format_cover_call({ok,Calls},func)-> - ["<TR BGCOLOR=\"#8899AA\"><TD COLSPAN=5><B>Function calls</B></TD></TR>\n", - "<TR><TD><I>Module</I></TD><TD><I>Function</I></TD>", - "<TD COLSPAN=2 ALIGN=\"right\"><I>Arity</I></TD>", - "<TD ALIGN=\"right\"><I>Number of calls </I></TD></TR>\n", - lists:append( - lists:map( - fun({{Mod,Func,Arity},Nr_of_calls})-> - ["<TR><TD WIDTH=\"20%\">"++ atom_to_list(Mod)++"</TD>\n", - "<TD WIDTH=\"20%\" >" ++ atom_to_list(Func) ++" </TD>\n", - "<TD COLSPAN=2 WIDTH=\"40%\" ALIGN=\"right\">", - integer_to_list(Arity), - "</TD>\n", - "<TD WIDTH=\"20%\" ALIGN=\"right\">", - integer_to_list(Nr_of_calls), - "</TD></TR>\n"] - end, - Calls))]; - -format_cover_call({ok,Calls},clause)-> - ["<TR BGCOLOR=\"#8899AA\"><TD COLSPAN=5><B>Clause calls</B></TD></TR>\n", - "<TR><TD><I>Module</I></TD><TD><I>Function</I></TD>", - "<TD ALIGN=\"right\"><I>Arity</I></TD>", - "<TD ALIGN=\"right\"><I>Ordinal</I></TD>", - "<TD ALIGN=\"right\"><I>Number of calls</I></TD></TR>\n", - lists:append( - lists:map( - fun({{Mod,Func,Arity,Ord},Nr_of_calls})-> - ["<TR><TD WIDTH=\"20%\" >", atom_to_list(Mod), "</TD>\n", - "<TD WIDTH=\"20%\" >", atom_to_list(Func), "</TD>\n", - "<TD WIDTH=\"20%\" ALIGN=\"right\">", - integer_to_list(Arity), - "</TD>\n", - "<TD WIDTH=\"20%\" ALIGN=\"right\">", - integer_to_list(Ord), - "</TD>\n", - "<TD WIDTH=\"20%\" ALIGN=\"right\">", - integer_to_list(Nr_of_calls), - "</TD></TR>\n"] - end, - Calls))]. - - -error_body()-> - ["<TABLE WIDTH=\"100%\" BORDER=1>\n", - "<TR ALIGN=\"center\">\n", - "<TD>\n", - "<BR><BR><BR><BR><BR><BR>\n", - "<FONT SIZE=5>The selected module is not Cover Compiled</FONT>\n", - "<BR>\n", - "</TD>\n", - "</TR>\n", - "</TABLE>\n"]. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% The functions that builds the body of the page that shows coverage % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -coverage_result(Input)-> - Mod = list_to_atom(get_input_data(Input, "module")), - case cover:analyse(Mod,coverage) of - {error,_}-> - error_body(); - {ok,_} -> - coverage_result2(Mod,Input) - end. - -coverage_result2(Mod,Input)-> - Result = - case get_input_data(Input,"what") of - "mod" -> - coverage_result(mod,Mod); - "func" -> - coverage_result(func,Mod); - "clause" -> - coverage_result(clause,Mod); - _-> - coverage_result(all,Mod) - end, - result_choice("coverage",Mod) ++ Result. - -coverage_result(Mode,Module)-> - Content = - case Mode of - mod-> - format_cover_coverage(cover:analyse(Module,coverage,module), - mod); - func-> - format_cover_coverage(cover:analyse(Module,coverage,function), - func); - clause-> - format_cover_coverage(cover:analyse(Module,coverage,clause), - clause); - _-> - format_cover_coverage(cover:analyse(Module,coverage,module), - mod) ++ - format_cover_coverage(cover:analyse(Module,coverage,function), - func)++ - format_cover_coverage(cover:analyse(Module,coverage,clause), - clause) - end, - getModDate(Module,date())++"<BR>"++ - "<TABLE WIDTH=\"100%\" BORDER=1>" - ++ Content ++"</TABLE>". - -getModDate(Module,{Year,Mon,Day})-> - "<TABLE> - <TR> - <TD>Module:</TD> - <TD>" ++ atom_to_list(Module) ++ "</TD> - </TR> - <TR> - <TD>Date:</TD> - <TD>" ++ integer_to_list(Day) ++ "/" ++ - integer_to_list(Mon) ++" - "++ - integer_to_list(Year) ++ - "</TD> - </TR> - </TABLE>". - - -format_cover_coverage({error,_},_)-> - "<TR><TD> - <BR><BR><BR><BR> - <FONT SIZE=5>The selected module is not Cover Compiled</FONT> - <BR> - </TD></TR>"; - - -format_cover_coverage({ok,{Mod,{Cov,Not_cov}}},mod)-> - ["<TR BGCOLOR=\"#8899AA\"><TD COLSPAN=6><B>Module coverage</B></TD></TR>\n", - "<TR><TD COLSPAN=4><I>Module</I></TD>\n", - "<TD ALIGN=\"right\"><I>Covered</I></TD>\n" - "<TD ALIGN=\"RIGHT\" NOWRAP=\"true\"><I>Not Covered</I></TD>\n", - "</TR>\n", - "<TR><TD COLSPAN=4>", atom_to_list(Mod), "</TD>\n" - "<TD ALIGN=\"right\">", integer_to_list(Cov), "</TD>\n" - "<TD ALIGN=\"right\" >", integer_to_list(Not_cov), "</TD></TR>\n"]; - -format_cover_coverage({ok,Cov_res},func)-> - ["<TR BGCOLOR=\"#8899AA\"><TD COLSPAN=6><B>Function coverage</B></TD>\n", - "</TR>\n", - "<TR><TD><I>Module</I></TD><TD><I>Function</I></TD>", - "<TD ALIGN=\"right\"><I>Arity</I></TD>", - "<TD COLSPAN=2 ALIGN=\"right\"><I>Covered</I></TD>", - "<TD ALIGN=\"right\" STYLE=\"white-space:nowrap\"><I>Not Covered</I></TD>", - "</TR>\n", - lists:append( - lists:map( - fun({{Mod,Func,Arity},{Cov,Not_cov}})-> - ["<TR><TD WIDTH=\"20%\" >"++ atom_to_list(Mod) ++" </TD>\n", - "<TD WIDTH=\"20%\" >" ++ atom_to_list(Func) ++"</TD>\n", - "<TD WIDTH=\"40%\" ALIGN=\"right\">", - integer_to_list(Arity), - "</TD>\n", - "<TD WIDTH=\"40%\" ALIGN=\"right\" COLSPAN=2>", - integer_to_list(Cov), - "</TD>\n" - "<TD WIDTH=\"20%\" ALIGN=\"right\">", - integer_to_list(Not_cov), - "</TD></TR>\n"] - end, - Cov_res))]; - -format_cover_coverage({ok,Cov_res},clause)-> - ["<TR BGCOLOR=\"#8899AA\"><TD COLSPAN=6><B>Clause coverage</B></TD></TR>\n", - "<TR><TD><I>Module</I></TD><TD><I>Function</I></TD>\n", - "<TD ALIGN=\"right\"><I>Arity</I></TD>\n", - "<TD ALIGN=\"right\"><I>Ordinal<I></TD>\n", - "<TD ALIGN=\"right\">Covered</TD>\n", - "<TD ALIGN=\"right\" STYLE=\"white-space:nowrap\">Not Covered</TD></TR>\n", - lists:append( - lists:map( - fun({{Mod,Func,Arity,Ord},{Cov,Not_cov}})-> - ["<TR><TD WIDTH=\"20%\" >"++ atom_to_list(Mod) ++"</TD>\n", - "<TD WIDTH=\"20%\" >" ++ atom_to_list(Func) ++" </TD>\n", - "<TD WIDTH=\"20%\" ALIGN=\"right\">", - integer_to_list(Arity), - "</TD>\n" - "<TD WIDTH=\"20%\" ALIGN=\"right\">", - integer_to_list(Ord), - "</TD>\n" - "<TD WIDTH=\"20%\" ALIGN=\"right\">", - integer_to_list(Cov), - "</TD>\n" - "<TD WIDTH=\"20%\" ALIGN=\"right\">", - integer_to_list(Not_cov), - "</TD></TR>\n"] - end, - Cov_res))]. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% The functions that builds the body of the import page % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -import_body(Dir,Err) -> - [reload_menu_script(Err), - "<H1 ALIGN=center>Import</H1>\n", - "<TABLE BORDER=0 WIDTH=600 ALIGN=center>\n", - "<TR><TD BGCOLOR=",?INFO_BG_COLOR,">\n", - "<P>You can import coverage data from a previous analysis. If you do so\n", - "the imported data will be merged with the current coverage data.\n", - "<P>You can export data from the current analysis from the \"Result\"\n", - "page.\n", - "<P>Select the file to import here.\n", - "</TD></TR>\n", - "<TR><TD ALIGN=center><BR><BR>\n", - "<FORM NAME=change_import_dir METHOD=post ACTION=\"./import\">\n", - "<B>Change directory:</B><BR>\n", - "<INPUT TYPE=text NAME=\"file\" SIZE=30 VALUE=",Dir,">", - "<INPUT TYPE=hidden NAME=dir VALUE=",Dir,">\n", - "<INPUT TYPE=submit VALUE=Ok><BR>\n", - "</FORM>\n", - browse_import(Dir), - "</TABLE>"]. - -browse_import(Dir) -> - {ok,List} = file:list_dir(Dir), - Sorted = lists:reverse(lists:sort(List)), - {Dirs,Files} = filter_files(Dir,Sorted,[],[]), - ["<FORM NAME=browse_import METHOD=post ACTION=\"./import\">\n" - "<SELECT NAME=file TITLE=\"Select import file\" SIZE=10>\n", - "<OPTION VALUE=\"..\" onDblClick=submit()>../</OPTION>\n", - Dirs, - Files, - "</SELECT>\n", - "<INPUT TYPE=hidden NAME=dir VALUE=",Dir,">\n", - "<BR><INPUT TYPE=submit VALUE=Ok>\n" - "</FORM>\n"]. - -filter_files(Dir,[File|Files],Ds,Fs) -> - case filename:extension(File) of - ".coverdata" -> - Fs1 = ["<OPTION VALUE=",File," onDblClick=submit()>", - File,"</OPTION>\n" | Fs], - filter_files(Dir,Files,Ds,Fs1); - _ -> - FullName = filename:join(Dir,File), - case filelib:is_dir(FullName) of - true -> - Ds1 = ["<OPTION VALUE=",File," onDblClick=submit()>", - File,"/</OPTION>\n" | Ds], - filter_files(Dir,Files,Ds1,Fs); - false -> - filter_files(Dir,Files,Ds,Fs) - end - end; -filter_files(_Dir,[],Ds,Fs) -> - {Ds,Fs}. - - - - -do_import(Input) -> - case parse(Input) of - [{"file",File0},{"dir",Dir}] -> - File = filename:join(Dir,File0), - case filelib:is_dir(File) of - true -> - import_frame1(File); - false -> - case filelib:is_file(File) of - true -> - case cover:import(File) of - ok -> - import_frame1(Dir); - {error,{cant_open_file,ExportFile,_Reason}} -> - import_frame1(Dir, - "Error importing file\\n\\\"" - ++ ExportFile ++ "\\\"") - end; - false -> - import_frame1(Dir, - "Error importing file\\n\\\"" ++ - File ++ "\\\"") - end - end; - [{"dir",Dir}] -> - import_frame1(Dir,"No file is selected") - end. - - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% Different private helper functions % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%Create the Header for the page If we now the mimetype use that type %% -%%otherwise use text %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -header() -> - header("text/html"). -header(MimeType) -> - "Pragma:no-cache\r\n" ++ - "Content-type: " ++ MimeType ++ "\r\n\r\n". - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%Create the Htmlheader set the title of the page %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -html_header(Title) -> - "<HTML>\n" ++ - "<HEAD>\n" ++ - "<TITLE>" ++ Title ++ "</TITLE>\n" ++ - "</HEAD>\n" - "<BODY BGCOLOR=\"#FFFFFF\">\n". - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Close the body- and Html tags %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -html_end()-> - "</BODY></HTML>". - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% A script which reloads the menu frame and possibly pops up an alert%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -reload_menu_script(Err) -> - ["<SCRIPT>\n", - "function reloadMenu()\n", - " {\n", - " parent.menu.document.location.href=\"./menu_frame\";\n", - case Err of - "" -> ""; - _ -> " alert(\""++Err++"\");\n" - end, - case get_warnings() of - [] -> - ""; - Warnings -> - " alert(\""++fix_newline(lists:flatten(Warnings))++"\");\n" - end, - " }\n", - "</SCRIPT>\n", - "<BODY onLoad=reloadMenu() BGCOLOR=\"#FFFFFF\">"]. - -fix_newline([$\n|Rest]) -> - [$\\,$n|fix_newline(Rest)]; -fix_newline([$"|Rest]) -> - [$\\,$"|fix_newline(Rest)]; -fix_newline([Char|Rest]) -> - [Char|fix_newline(Rest)]; -fix_newline([]) -> - []. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Control the input data and return the intresting values or error % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -get_input_data(Input,Key)-> - case lists:keysearch(Key,1,parse(Input)) of - {value,{Key,Value}} -> - Value; - false -> - undefined - end. - -parse(Input) -> - httpd:parse_query(Input). - - -get_warnings() -> - cover_group_leader_proc ! {self(), get_warnings}, - receive {warnings,Warnings} -> - Warnings - end. diff --git a/lib/tools/src/cprof.erl b/lib/tools/src/cprof.erl index b0c3341efa..f6d68f0bf8 100644 --- a/lib/tools/src/cprof.erl +++ b/lib/tools/src/cprof.erl @@ -1,18 +1,19 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2009. All Rights Reserved. +%% Copyright Ericsson AB 2002-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% @@ -113,6 +114,7 @@ analyse(Limit) when is_integer(Limit) -> analyse(M) when is_atom(M) -> analyse(M, 1). +-dialyzer({no_improper_lists, analyse/2}). analyse(M, Limit) when is_atom(M), is_integer(Limit) -> L0 = [begin MFA = {M,F,A}, diff --git a/lib/tools/src/eprof.erl b/lib/tools/src/eprof.erl index bfbbefb473..07e995993b 100644 --- a/lib/tools/src/eprof.erl +++ b/lib/tools/src/eprof.erl @@ -1,18 +1,19 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% 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 %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% @@ -187,7 +188,7 @@ handle_call({profile_start, Rootset, Pattern, {M,F,A}, Opts}, From, #state{fd = case set_process_trace(true, [Pid|Rootset], Topts) of true -> ok = set_pattern_trace(true, Pattern), - T0 = now(), + T0 = erlang:timestamp(), ok = execute_profiling(Pid), {noreply, #state{ profiling = true, @@ -211,7 +212,7 @@ handle_call({profile_start, Rootset, Pattern, undefined, Opts}, From, #state{ fd case set_process_trace(true, Rootset, Topts) of true -> - T0 = now(), + T0 = erlang:timestamp(), ok = set_pattern_trace(true, Pattern), {reply, profiling, #state{ profiling = true, @@ -485,20 +486,22 @@ string_bp_mfa([{Mfa, {Count, Time}}|Mfas], Tus, {MfaW, CountW, PercW, TimeW, TpC erlang:max(TpCW, length(Stpc)) }, [[Smfa, Scount, Sperc, Stime, Stpc] | Strings]). -print_bp_mfa(Mfas, {_Tn, Tus}, Fd, Opts) -> +print_bp_mfa(Mfas, {Tn, Tus}, Fd, Opts) -> Fmfas = filter_mfa(sort_mfa(Mfas, proplists:get_value(sort, Opts)), proplists:get_value(filter, Opts)), {{MfaW, CountW, PercW, TimeW, TpCW}, Strs} = string_bp_mfa(Fmfas, Tus), - Ws = { - erlang:max(length("FUNCTION"), MfaW), - erlang:max(length("CALLS"), CountW), - erlang:max(length(" %"), PercW), - erlang:max(length("TIME"), TimeW), - erlang:max(length("uS / CALLS"), TpCW) - }, - format(Fd, Ws, ["FUNCTION", "CALLS", " %", "TIME", "uS / CALLS"]), - format(Fd, Ws, ["--------", "-----", "---", "----", "----------"]), - + TnStr = s(Tn), + TusStr = s(Tus), + TuspcStr = s("~.2f", [divide(Tus,Tn)]), + Ws = {erlang:max(length("FUNCTION"), MfaW), + lists:max([length("CALLS"), CountW, length(TnStr)]), + erlang:max(length(" %"), PercW), + lists:max([length("TIME"), TimeW, length(TusStr)]), + lists:max([length("uS / CALLS"), TpCW, length(TuspcStr)])}, + format(Fd, Ws, ["FUNCTION", "CALLS", " %", "TIME", "uS / CALLS"]), + format(Fd, Ws, ["--------", "-----", "-------", "----", "----------"]), lists:foreach(fun (String) -> format(Fd, Ws, String) end, Strs), + format(Fd, Ws, [lists:duplicate(N,$-)||N <- tuple_to_list(Ws)]), + format(Fd, Ws, ["Total:", TnStr, "100.00%", TusStr, TuspcStr]), ok. s({M,F,A}) -> s("~w:~w/~w",[M,F,A]); diff --git a/lib/tools/src/fprof.erl b/lib/tools/src/fprof.erl index 75840e54ff..b21eedc625 100644 --- a/lib/tools/src/fprof.erl +++ b/lib/tools/src/fprof.erl @@ -1,18 +1,19 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2013. All Rights Reserved. +%% Copyright Ericsson AB 2001-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% @@ -1566,13 +1567,20 @@ trace_handler({trace_ts, Pid, return_to, {_M, _F, Args} = MFArgs, TS} = Trace, trace_return_to(Table, Pid, Func, TS), TS; %% -%% spawn +%% spawn, only needed (and reliable) prior to 19.0 trace_handler({trace_ts, Pid, spawn, Child, MFArgs, TS} = Trace, Table, _, Dump) -> dump_stack(Dump, get(Pid), Trace), trace_spawn(Table, Child, MFArgs, TS, Pid), TS; %% +%% spawned, added in 19.0 +trace_handler({trace_ts, Pid, spawned, Parent, MFArgs, TS} = Trace, + Table, _, Dump) -> + dump_stack(Dump, get(Pid), Trace), + trace_spawn(Table, Pid, MFArgs, TS, Parent), + TS; +%% %% exit trace_handler({trace_ts, Pid, exit, _Reason, TS} = Trace, Table, _, Dump) -> @@ -1621,15 +1629,24 @@ trace_handler({trace_ts, Pid, in, {_M, _F, Args} = MFArgs, TS} = Trace, TS; %% %% gc_start -trace_handler({trace_ts, Pid, gc_start, _Func, TS} = Trace, - Table, _, Dump) -> +trace_handler({trace_ts, Pid, gc_minor_start, _Func, TS} = Trace, Table, _, Dump) -> + dump_stack(Dump, get(Pid), Trace), + trace_gc_start(Table, Pid, TS), + TS; + +trace_handler({trace_ts, Pid, gc_major_start, _Func, TS} = Trace, Table, _, Dump) -> dump_stack(Dump, get(Pid), Trace), trace_gc_start(Table, Pid, TS), TS; + %% %% gc_end -trace_handler({trace_ts, Pid, gc_end, _Func, TS} = Trace, - Table, _, Dump) -> +trace_handler({trace_ts, Pid, gc_minor_end, _Func, TS} = Trace, Table, _, Dump) -> + dump_stack(Dump, get(Pid), Trace), + trace_gc_end(Table, Pid, TS), + TS; + +trace_handler({trace_ts, Pid, gc_major_end, _Func, TS} = Trace, Table, _, Dump) -> dump_stack(Dump, get(Pid), Trace), trace_gc_end(Table, Pid, TS), TS; @@ -2013,8 +2030,10 @@ trace_spawn(Table, Pid, MFArgs, TS, Parent) -> ets:insert(Table, #proc{id = Pid, parent = Parent, spawned_as = MFArgs}); _ -> - throw({inconsistent_trace_data, ?MODULE, ?LINE, - [Pid, MFArgs, TS, Parent, Stack]}) + %% In 19.0 we get both a spawn and spawned event, + %% however we do not know the order so we just ignore + %% the second event that comes + ok end. @@ -2250,6 +2269,8 @@ do_analyse(Table, Analyse) -> ?dbg(5, "do_analyse_1(_, _) ->~p~n", [Result]), Result. +-dialyzer({no_improper_lists, do_analyse_1/2}). + do_analyse_1(Table, #analyse{group_leader = GroupLeader, dest = Io, @@ -2623,6 +2644,8 @@ funcstat_pd(Pid, Func1, Func0, Clocks) -> funcstat_sort_r(FuncstatList, Element) -> funcstat_sort_r_1(FuncstatList, Element, []). +-dialyzer({no_improper_lists, funcstat_sort_r_1/3}). + funcstat_sort_r_1([], _, R) -> postsort_r(lists:sort(R)); funcstat_sort_r_1([#funcstat{callers_sum = #clocks{} = Clocks, @@ -2645,6 +2668,8 @@ funcstat_sort_r_1([#funcstat{callers_sum = #clocks{} = Clocks, clocks_sort_r(L, E) -> clocks_sort_r_1(L, E, []). +-dialyzer({no_improper_lists, clocks_sort_r_1/3}). + clocks_sort_r_1([], _, R) -> postsort_r(lists:sort(R)); clocks_sort_r_1([#clocks{} = C | L], E, R) -> diff --git a/lib/tools/src/instrument.erl b/lib/tools/src/instrument.erl index fa8a4a4867..055f4a7afb 100644 --- a/lib/tools/src/instrument.erl +++ b/lib/tools/src/instrument.erl @@ -1,18 +1,19 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% Copyright Ericsson AB 1998-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% diff --git a/lib/tools/src/lcnt.erl b/lib/tools/src/lcnt.erl index d5ba8aa52f..78407a651a 100644 --- a/lib/tools/src/lcnt.erl +++ b/lib/tools/src/lcnt.erl @@ -1,18 +1,19 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2013. All Rights Reserved. +%% Copyright Ericsson AB 2010-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% 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 %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% @@ -93,12 +94,12 @@ -record(stats, { file :: atom(), - line :: non_neg_integer(), + line :: non_neg_integer() | 'undefined', tries :: non_neg_integer(), colls :: non_neg_integer(), time :: non_neg_integer(), % us nt :: non_neg_integer(), % #timings collected - hist :: tuple() % histogram + hist :: tuple() | 'undefined' % histogram }). -record(lock, { @@ -756,7 +757,7 @@ list2lock([F|Fs], Ls) -> stats2stats([]) -> []; stats2stats([Stat|Stats]) -> - Sz = tuple_size(#stats{}), + Sz = record_info(size, stats), [stat2stat(Stat,Sz)|stats2stats(Stats)]. stat2stat(Stat,Sz) when tuple_size(Stat) =:= Sz -> Stat; @@ -932,7 +933,6 @@ strings(Strings) -> strings(Strings, []). strings([], Out) -> Out; strings([{space, N, S} | Ss], Out) -> strings(Ss, Out ++ term2string(term2string("~~~ws", [N]), [S])); strings([{left, N, S} | Ss], Out) -> strings(Ss, Out ++ term2string(term2string(" ~~s~~~ws", [N]), [S,""])); -strings([{format, Format, S} | Ss], Out) -> strings(Ss, Out ++ term2string(Format, [S])); strings([S|Ss], Out) -> strings(Ss, Out ++ term2string("~ts", [S])). diff --git a/lib/tools/src/make.erl b/lib/tools/src/make.erl index c8ef0a04a5..26378f28a0 100644 --- a/lib/tools/src/make.erl +++ b/lib/tools/src/make.erl @@ -1,18 +1,19 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% @@ -24,12 +25,20 @@ %% If Emakefile is missing the current directory is used. -module(make). --export([all/0,all/1,files/1,files/2]). +-export([all_or_nothing/0,all/0,all/1,files/1,files/2]). -include_lib("kernel/include/file.hrl"). -define(MakeOpts,[noexec,load,netload,noload]). +all_or_nothing() -> + case all() of + up_to_date -> + up_to_date; + error -> + halt(1) + end. + all() -> all([]). @@ -290,10 +299,11 @@ check_includes(File, IncludePath, ObjMTime) -> end. check_includes2(Epp, File, ObjMTime) -> + A1 = erl_anno:new(1), case epp:parse_erl_form(Epp) of - {ok, {attribute, 1, file, {File, 1}}} -> + {ok, {attribute, A1, file, {File, A1}}} -> check_includes2(Epp, File, ObjMTime); - {ok, {attribute, 1, file, {IncFile, 1}}} -> + {ok, {attribute, A1, file, {IncFile, A1}}} -> case file:read_file_info(IncFile) of {ok, #file_info{mtime=MTime}} when MTime>ObjMTime -> epp:close(Epp), diff --git a/lib/tools/src/tags.erl b/lib/tools/src/tags.erl index e25db2eb1b..2bc1865503 100644 --- a/lib/tools/src/tags.erl +++ b/lib/tools/src/tags.erl @@ -3,16 +3,17 @@ %% %% Copyright Ericsson AB 1996-2015. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% diff --git a/lib/tools/src/tools.app.src b/lib/tools/src/tools.app.src index ec5b6f3a82..a00969eabe 100644 --- a/lib/tools/src/tools.app.src +++ b/lib/tools/src/tools.app.src @@ -1,18 +1,19 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2012. All Rights Reserved. +%% Copyright Ericsson AB 1996-2015. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% @@ -20,7 +21,6 @@ [{description, "DEVTOOLS CXC 138 16"}, {vsn, "%VSN%"}, {modules, [cover, - cover_web, eprof, fprof, instrument, @@ -35,13 +35,13 @@ xref_utils ] }, - {registered,[webcover_server]}, + {registered, []}, {applications, [kernel, stdlib]}, {env, [{file_util_search_methods,[{"", ""}, {"ebin", "esrc"}, {"ebin", "src"}]} ] }, - {runtime_dependencies, ["webtool-0.8.10","stdlib-2.0","runtime_tools-1.8.14", - "kernel-3.0","inets-5.10","erts-6.0", + {runtime_dependencies, ["stdlib-2.5","runtime_tools-1.8.14", + "kernel-3.0","inets-5.10","erts-7.0", "compiler-5.0"]} ] }. diff --git a/lib/tools/src/tools.appup.src b/lib/tools/src/tools.appup.src index 9a27456a81..fa48fa4219 100644 --- a/lib/tools/src/tools.appup.src +++ b/lib/tools/src/tools.appup.src @@ -1,18 +1,19 @@ %% -*- erlang -*- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2014. All Rights Reserved. +%% Copyright Ericsson AB 2001-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% 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 %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% {"%VSN%", diff --git a/lib/tools/src/xref.erl b/lib/tools/src/xref.erl index abc184c84d..32efa36fa2 100644 --- a/lib/tools/src/xref.erl +++ b/lib/tools/src/xref.erl @@ -1,18 +1,19 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2013. All Rights Reserved. +%% Copyright Ericsson AB 2000-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% diff --git a/lib/tools/src/xref.hrl b/lib/tools/src/xref.hrl index fa8c5c746d..a83271cbdb 100644 --- a/lib/tools/src/xref.hrl +++ b/lib/tools/src/xref.hrl @@ -1,18 +1,19 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% Copyright Ericsson AB 2000-2015. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% @@ -22,6 +23,8 @@ -define(VAR_EXPR, '$F_EXPR'). -define(MOD_EXPR, '$M_EXPR'). +-define(XREF_END_LINE, (1 bsl 23)). + %%% Filenames are stored as directory and basename. A lot of heap can %%% be saved by keeping only one (or few) copy of the directory name. diff --git a/lib/tools/src/xref_base.erl b/lib/tools/src/xref_base.erl index 30c5f3d12d..70eb107781 100644 --- a/lib/tools/src/xref_base.erl +++ b/lib/tools/src/xref_base.erl @@ -1,18 +1,19 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2013. All Rights Reserved. +%% Copyright Ericsson AB 2000-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% 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 %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% diff --git a/lib/tools/src/xref_compiler.erl b/lib/tools/src/xref_compiler.erl index c4b5c04c12..8c87e47c4c 100644 --- a/lib/tools/src/xref_compiler.erl +++ b/lib/tools/src/xref_compiler.erl @@ -1,18 +1,19 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2014. All Rights Reserved. +%% Copyright Ericsson AB 2000-2015. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% 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 %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% @@ -924,7 +925,7 @@ format_parse_error(["invalid_operator", Op], Line) -> format_parse_error(Error, Line) -> io_lib:format("Parse error~s: ~ts~n", [Line, lists:flatten(Error)]). -format_line(-1) -> +format_line(?XREF_END_LINE) -> " at end of string"; format_line(0) -> ""; diff --git a/lib/tools/src/xref_parser.yrl b/lib/tools/src/xref_parser.yrl index 1279ece061..0711da79e2 100644 --- a/lib/tools/src/xref_parser.yrl +++ b/lib/tools/src/xref_parser.yrl @@ -1,18 +1,19 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2010. All Rights Reserved. +%% Copyright Ericsson AB 2000-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% 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 %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% diff --git a/lib/tools/src/xref_reader.erl b/lib/tools/src/xref_reader.erl index 142d28ebe6..41b93caaeb 100644 --- a/lib/tools/src/xref_reader.erl +++ b/lib/tools/src/xref_reader.erl @@ -1,18 +1,19 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2013. All Rights Reserved. +%% Copyright Ericsson AB 2000-2015. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% 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 %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% @@ -77,17 +78,18 @@ forms([], S) -> form({attribute, Line, xref, Calls}, S) -> % experimental #xrefr{module = M, function = Fun, lattrs = L, xattrs = X, battrs = B} = S, - attr(Calls, Line, M, Fun, L, X, B, S); + attr(Calls, erl_anno:line(Line), M, Fun, L, X, B, S); form({attribute, _Line, _Attr, _Val}, S) -> S; -form({function, 0, module_info, 0, _Clauses}, S) -> +form({function, _, module_info, 0, _Clauses}, S) -> S; -form({function, 0, module_info, 1, _Clauses}, S) -> +form({function, _, module_info, 1, _Clauses}, S) -> S; -form({function, Line, Name, Arity, Clauses}, S) -> +form({function, Anno, Name, Arity, Clauses}, S) -> MFA0 = {S#xrefr.module, Name, Arity}, MFA = adjust_arity(S, MFA0), S1 = S#xrefr{function = MFA}, + Line = erl_anno:line(Anno), S2 = S1#xrefr{def_at = [{MFA,Line} | S#xrefr.def_at]}, S3 = clauses(Clauses, S2), S3#xrefr{function = []}. @@ -305,10 +307,14 @@ fun_args(apply2, [FunArg, Args]) -> {FunArg, Args}; fun_args(1, [FunArg | Args]) -> {FunArg, Args}; fun_args(2, [_Node, FunArg | Args]) -> {FunArg, Args}. -list2term([A | As]) -> - {cons, 0, A, list2term(As)}; -list2term([]) -> - {nil, 0}. +list2term(L) -> + A = erl_anno:new(0), + list2term(L, A). + +list2term([A | As], Anno) -> + {cons, Anno, A, list2term(As)}; +list2term([], Anno) -> + {nil, Anno}. term2list({cons, _Line, H, T}, L, S) -> term2list(T, [H | L], S); @@ -335,10 +341,11 @@ handle_call(Locality, Module, Name, Arity, Line, S) -> handle_call(Locality, To, Line, S, false) end. -handle_call(Locality, To0, Line, S, IsUnres) -> +handle_call(Locality, To0, Anno, S, IsUnres) -> From = S#xrefr.function, To = adjust_arity(S, To0), Call = {From, To}, + Line = erl_anno:line(Anno), CallAt = {Call, Line}, S1 = if IsUnres -> diff --git a/lib/tools/src/xref_scanner.erl b/lib/tools/src/xref_scanner.erl index 990f8aa87b..0b14159fbe 100644 --- a/lib/tools/src/xref_scanner.erl +++ b/lib/tools/src/xref_scanner.erl @@ -1,24 +1,27 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% Copyright Ericsson AB 2000-2015. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% -module(xref_scanner). +-include("xref.hrl"). + -export([scan/1]). scan(Chars) -> @@ -77,7 +80,7 @@ lex([V={var,N,Var} | L]) -> lex([T | Ts]) -> [T | lex(Ts)]; lex([]) -> - [{'$end', -1}]. + [{'$end', erl_anno:new(?XREF_END_LINE)}]. is_type('Rel') -> true; is_type('App') -> true; diff --git a/lib/tools/src/xref_utils.erl b/lib/tools/src/xref_utils.erl index 49c397a140..f69aa70244 100644 --- a/lib/tools/src/xref_utils.erl +++ b/lib/tools/src/xref_utils.erl @@ -1,18 +1,19 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2014. All Rights Reserved. +%% Copyright Ericsson AB 2000-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% 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 %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% @@ -244,6 +245,8 @@ select_last_application_version(AppVs) -> TL = to_external(partition(1, relation(AppVs))), [last(keysort(2, L)) || L <- TL]. +-record(scan, {collected = [], errors = [], seen = [], unreadable = []}). + %% scan_directory(Directory, Recurse, Collect, Watch) -> %% {Collected, Errors, Seen, Unreadable} %% @@ -260,8 +263,9 @@ select_last_application_version(AppVs) -> %% Unreadable. %% scan_directory(File, Recurse, Collect, Watch) -> - Init = [[] | {[],[],[]}], - [L | {E,J,U}] = find_files_dir(File, Recurse, Collect, Watch, Init), + Init = #scan{}, + S = find_files_dir(File, Recurse, Collect, Watch, Init), + #scan{collected = L, errors = E, seen = J, unreadable = U} = S, {reverse(L), reverse(E), reverse(J), reverse(U)}. %% {Dir, Basename} | false @@ -575,8 +579,7 @@ find_files_dir(Dir, Recurse, Collect, Watch, L) -> {ok, Files} -> find_files(sort(Files), Dir, Recurse, Collect, Watch, L); {error, Error} -> - [B | {E,J,U}] = L, - [B | {[file_error(Dir, Error)|E],J,U}] + L#scan{errors = [file_error(Dir, Error)|L#scan.errors]} end. find_files([F | Fs], Dir, Recurse, Collect, Watch, L) -> @@ -587,22 +590,23 @@ find_files([F | Fs], Dir, Recurse, Collect, Watch, L) -> {ok, {_, directory, _, _}} -> L; Info -> - [B | EJU = {E,J,U}] = L, + #scan{collected = B, errors = E, + seen = J, unreadable = U} = L, Ext = filename:extension(File), C = member(Ext, Collect), case C of true -> case Info of {ok, {_, file, readable, _}} -> - [[{Dir,F} | B] | EJU]; + L#scan{collected = [{Dir,F} | B]}; {ok, {_, file, unreadable, _}} -> - [B | {E,J,[File|U]}]; + L#scan{unreadable = [File|U]}; Error -> - [B | {[Error|E],J,U}] + L#scan{errors = [Error|E]} end; false -> case member(Ext, Watch) of - true -> [B | {E,[File|J],U}]; + true -> L#scan{seen = [File|J]}; false -> L end end diff --git a/lib/tools/test/Makefile b/lib/tools/test/Makefile index 484cfdf53f..84c4e56aff 100644 --- a/lib/tools/test/Makefile +++ b/lib/tools/test/Makefile @@ -1,18 +1,19 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2012. All Rights Reserved. +# Copyright Ericsson AB 1997-2016. All Rights Reserved. # -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. +# 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 # -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. +# 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. # # %CopyrightEnd% # @@ -52,8 +53,7 @@ RELSYSDIR = $(RELEASE_PATH)/tools_test # FLAGS # ---------------------------------------------------- ERL_MAKE_FLAGS += -ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/test_server/include \ - -I$(ERL_TOP)/lib/percept/include +ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/percept/include EBIN = . diff --git a/lib/tools/test/cover_SUITE.erl b/lib/tools/test/cover_SUITE.erl index 80807b1d38..b4c9264b30 100644 --- a/lib/tools/test/cover_SUITE.erl +++ b/lib/tools/test/cover_SUITE.erl @@ -1,94 +1,65 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2013. All Rights Reserved. +%% Copyright Ericsson AB 2001-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% -module(cover_SUITE). --export([all/0, init_per_testcase/2, end_per_testcase/2, - suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2]). - --export([coverage/1, coverage_analysis/1, - start/1, compile/1, analyse/1, misc/1, stop/1, - distribution/1, reconnect/1, die_and_reconnect/1, - dont_reconnect_after_stop/1, stop_node_after_disconnect/1, - export_import/1, - otp_5031/1, eif/1, otp_5305/1, otp_5418/1, otp_6115/1, otp_7095/1, - otp_8188/1, otp_8270/1, otp_8273/1, otp_8340/1, - otp_10979_hanging_node/1, compile_beam_opts/1, eep37/1]). +-compile(export_all). --export([do_coverage/1]). +-include_lib("common_test/include/ct.hrl"). --include_lib("test_server/include/test_server.hrl"). - -%%---------------------------------------------------------------------- -%% The following directory structure is assumed: -%% cwd __________________________________________ -%% | \ \ \ \ \ \ \ -%% a b cc d f d1 compile_beam_____ otp_6115 -%% | \ \ \ \ \ \ \ -%% e crypt v w x d f1 f2 -%% | -%% y -%%---------------------------------------------------------------------- - -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> + [{ct_hooks,[ts_install_cth]}]. all() -> NoStartStop = [eif,otp_5305,otp_5418,otp_7095,otp_8273, - otp_8340,otp_8188,compile_beam_opts,eep37], + otp_8340,otp_8188,compile_beam_opts,eep37, + analyse_no_beam, line_0, compile_beam_no_file, + otp_13277, otp_13289], StartStop = [start, compile, analyse, misc, stop, - distribution, reconnect, die_and_reconnect, - dont_reconnect_after_stop, stop_node_after_disconnect, - export_import, otp_5031, otp_6115, - otp_8270, otp_10979_hanging_node], + distribution, reconnect, die_and_reconnect, + dont_reconnect_after_stop, stop_node_after_disconnect, + export_import, otp_5031, otp_6115, + otp_8270, otp_10979_hanging_node], case whereis(cover_server) of - undefined -> - [coverage,StartStop ++ NoStartStop]; - _pid -> - [coverage|NoStartStop++[coverage_analysis]] + undefined -> + [coverage,StartStop ++ NoStartStop]; + _pid -> + [coverage|NoStartStop++[coverage_analysis]] end. -groups() -> - []. - init_per_suite(Config) -> [{ct_is_running_cover,whereis(cover_server) =/= undefined}|Config]. end_per_suite(_Config) -> ok. -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - init_per_testcase(TC, Config) when TC =:= misc; - TC =:= compile; - TC =:= analyse; - TC =:= distribution; - TC =:= otp_5031; - TC =:= stop -> + TC =:= compile; + TC =:= analyse; + TC =:= distribution; + TC =:= otp_5031; + TC =:= stop -> case code:which(crypto) of - Path when is_list(Path) -> - init_per_testcase(dummy_tc, Config); - _Else -> - {skip, "No crypto file to test with"} + Path when is_list(Path) -> + init_per_testcase(dummy_tc, Config); + _Else -> + {skip, "No crypto file to test with"} end; init_per_testcase(_TestCase, Config) -> Config. @@ -96,10 +67,10 @@ init_per_testcase(_TestCase, Config) -> end_per_testcase(TestCase, Config) -> NoStop = [start,compile,analyse,misc], DontStop = proplists:get_bool(ct_is_running_cover, Config) orelse - lists:member(TestCase, NoStop), + lists:member(TestCase, NoStop), case DontStop of - true -> ok; - false -> cover:stop() + true -> ok; + false -> cover:stop() end, ok. @@ -108,7 +79,7 @@ coverage(Config) when is_list(Config) -> ?MODULE:do_coverage(Config). do_coverage(Config) -> - Outdir = ?config(priv_dir, Config), + Outdir = proplists:get_value(priv_dir, Config), ExportFile = filename:join(Outdir, "export"), ok = cover:export(ExportFile, ?MODULE), {error,{already_started,_}} = cover:start(), @@ -121,16 +92,16 @@ do_coverage(Config) -> %% Cover escaping of '&' in HTML files. case proplists:get_bool(ct_is_running_cover, Config) of - false -> - %% Cover server was implicitly started when this module - %% was cover-compiled. We must stop the cover server, but - %% we must ensure that this module is not on the call - %% stack when it is unloaded. Therefore, the call that - %% follows MUST be tail-recursive. - cover:stop(); - true -> - %% Cover server was started by common_test; don't stop it. - ok + false -> + %% Cover server was implicitly started when this module + %% was cover-compiled. We must stop the cover server, but + %% we must ensure that this module is not on the call + %% stack when it is unloaded. Therefore, the call that + %% follows MUST be tail-recursive. + cover:stop(); + true -> + %% Cover server was started by common_test; don't stop it. + ok end. %% This test case will only be run when common_test is running cover. @@ -141,7 +112,7 @@ coverage_analysis(Config) when is_list(Config) -> io:format("~p\n", [Analysis2]), {ok,_Analysis3} = cover:analyze(?MODULE, calls, line), - Outdir = ?config(priv_dir, Config), + Outdir = proplists:get_value(priv_dir, Config), Outfile = filename:join(Outdir, ?MODULE), {ok,Outfile} = cover:analyze_to_file(?MODULE, Outfile), @@ -151,81 +122,90 @@ coverage_analysis(Config) when is_list(Config) -> {ok,Outfile} = cover:analyze_to_file(?MODULE, Outfile, [html]), ok. -start(suite) -> []; start(Config) when is_list(Config) -> - ?line ok = file:set_cwd(?config(data_dir, Config)), + ok = file:set_cwd(proplists:get_value(data_dir, Config)), - ?line Files = lsfiles(), - ?line remove(files(Files, ".out")), + Files = lsfiles(), + remove(files(Files, ".out")), - ?line {ok, Pid} = cover:start(), - ?line {error, {already_started, Pid}} = cover:start(). + {ok, Pid} = cover:start(), + {error, {already_started, Pid}} = cover:start(). -compile(suite) -> []; compile(Config) when is_list(Config) -> - ?line ok = file:set_cwd(?config(data_dir, Config)), - - ?line Result1 = cover:compile_directory(), - ?line SortedResult = lists:sort(Result1), - ?line {ok, CWD} = file:get_cwd(), - ?line Result2 = cover:compile_directory(CWD), - ?line SortedResult = lists:sort(Result2), - ?line [{error,_DFile},{ok,a},{ok,b},{ok,cc},{ok,f}] = SortedResult, - ?line [{ok,e}] = cover:compile_directory("d1"), - ?line {error,enoent} = cover:compile_directory("d2"), - - ?line {ok,a} = cover:compile(a), - ?line {ok,b} = compile:file(b), - ?line code:purge(b), - ?line {module,b} = code:load_file(b), - ?line {ok,d} = cover:compile("d.erl", [{d,'AGE',42}]), - ?line {error,_BBFile} = cover:compile(bb), - - ?line StdlibDir = code:lib_dir(stdlib), - ?line Lists = filename:join([StdlibDir, "src", "lists.erl"]), - ?line {error, Lists} = cover:compile(Lists), + ok = file:set_cwd(proplists:get_value(data_dir, Config)), + + Result1 = cover:compile_directory(), + SortedResult = lists:sort(Result1), + {ok, CWD} = file:get_cwd(), + Result2 = cover:compile_directory(CWD), + SortedResult = lists:sort(Result2), + [{error,DFile},{ok,a},{ok,b},{ok,cc},{ok,f}] = SortedResult, + [{ok,e}] = cover:compile_directory("d1"), + {error,enoent} = cover:compile_directory("d2"), + + [] = cover:compile([]), + Result21 = cover:compile([a,b,"cc.erl",d,"f"]), + SortedResult21 = lists:sort(Result21), + [{error,DFile},{ok,a},{ok,b},{ok,cc},{ok,f}] = SortedResult21, + + {ok,a} = cover:compile(a), + {ok,b} = compile:file(b), + code:purge(b), + {module,b} = code:load_file(b), + {ok,d} = cover:compile("d.erl", [{d,'AGE',42}]), + {error,_BBFile} = cover:compile(bb), + + StdlibDir = code:lib_dir(stdlib), + Lists = filename:join([StdlibDir, "src", "lists.erl"]), + {error, Lists} = cover:compile(Lists), %% For compiling beam: using dummy files v,w,x,y and z - ?line file:set_cwd("compile_beam"), - ?line {ok,_} = compile:file(v,[debug_info,report]), - ?line {ok,_} = compile:file(w,[debug_info,report]), - ?line {ok,_} = compile:file(x), - ?line {ok,_} = compile:file("d/y",[debug_info,{outdir,"d"},report]), - ?line Key = "A Krypto Key", + file:set_cwd("compile_beam"), + {ok,_} = compile:file(v,[debug_info,report]), + {ok,_} = compile:file(w,[debug_info,report]), + {ok,_} = compile:file(x), + {ok,_} = compile:file("d/y",[debug_info,{outdir,"d"},report]), + Key = "A Krypto Key", CryptoWorks = crypto_works(), case CryptoWorks of - false -> - {ok,_} = compile:file(crypt, [debug_info,report]), - {ok,crypt} = cover:compile_beam("crypt.beam"); - true -> - {ok,_} = compile:file(crypt, [{debug_info_key,Key},report]), - {error,{encrypted_abstract_code,_}} = - cover:compile_beam("crypt.beam"), - ok = beam_lib:crypto_key_fun(simple_crypto_fun(Key)), - {ok,crypt} = cover:compile_beam("crypt.beam") + false -> + {ok,_} = compile:file(crypt, [debug_info,report]), + {ok,crypt} = cover:compile_beam("crypt.beam"); + true -> + {ok,_} = compile:file(crypt, [{debug_info_key,Key},report]), + {error,{encrypted_abstract_code,_}} = + cover:compile_beam("crypt.beam"), + ok = beam_lib:crypto_key_fun(simple_crypto_fun(Key)), + {ok,crypt} = cover:compile_beam("crypt.beam") end, - Path = filename:join([?config(data_dir, Config), "compile_beam", "v.erl"]), - ?line {ok,v} = cover:compile_beam(v), + Path = filename:join([proplists:get_value(data_dir, Config), "compile_beam", "v.erl"]), + {ok,v} = cover:compile_beam(v), {source,Path} = lists:keyfind(source, 1, v:module_info(compile)), - ?line {ok,w} = cover:compile_beam("w.beam"), - ?line {error,{no_abstract_code,"./x.beam"}} = cover:compile_beam(x), - ?line {error,{already_cover_compiled,no_beam_found,a}}=cover:compile_beam(a), - ?line {error,non_existing} = cover:compile_beam(z), - ?line [{ok,y}] = cover:compile_beam_directory("d"), - ?line Result3 = lists:sort(cover:compile_beam_directory()), - ?line [{error,{no_abstract_code,_XBeam}},{ok,crypt},{ok,v},{ok,w}] = Result3, - ?line {error,enoent} = cover:compile_beam_directory("d2"), - ?line decompile([v,w,y]), - ?line Files = lsfiles(), - ?line remove(files(Files, ".beam")). + {ok,w} = cover:compile_beam("w.beam"), + {error,{no_abstract_code,"./x.beam"}} = cover:compile_beam(x), + {error,{already_cover_compiled,no_beam_found,a}}=cover:compile_beam(a), + {error,non_existing} = cover:compile_beam(z), + [{ok,y}] = cover:compile_beam_directory("d"), + Result3 = lists:sort(cover:compile_beam_directory()), + [{error,{no_abstract_code,XBeam}},{ok,crypt},{ok,v},{ok,w}] = Result3, + {error,enoent} = cover:compile_beam_directory("d2"), + + [] = cover:compile_beam([]), + Result31 = cover:compile_beam([crypt,"v.beam",w,"x"]), + SortedResult31 = lists:sort(Result31), + [{error,{no_abstract_code,XBeam}},{ok,crypt},{ok,v},{ok,w}] = SortedResult31, + + decompile([v,w,y]), + Files = lsfiles(), + remove(files(Files, ".beam")). crypto_works() -> try crypto:start() of - {error,{already_started,crypto}} -> true; - ok -> true + {error,{already_started,crypto}} -> true; + ok -> true catch - error:_ -> - false + error:_ -> + false end. simple_crypto_fun(Key) -> @@ -233,112 +213,171 @@ simple_crypto_fun(Key) -> ({debug_info, des3_cbc, crypt, _}) -> Key end. -analyse(suite) -> []; analyse(Config) when is_list(Config) -> - ?line ok = file:set_cwd(?config(data_dir, Config)), - - ?line done = a:start(5), - - ?line {ok, {a,{17,2}}} = cover:analyse(a, coverage, module), - ?line {ok, [{{a,start,1},{6,0}}, - {{a,stop,1},{0,1}}, - {{a,pong,1},{1,0}}, - {{a,loop,3},{5,1}}, - {{a,trycatch,1},{4,0}}, - {{a,exit_kalle,0},{1,0}}]} = cover:analyse(a, coverage, function), - ?line {ok, [{{a,start,1,1},{6,0}}, - {{a,stop,1,1},{0,1}}, - {{a,pong,1,1},{1,0}}, - {{a,loop,3,1},{3,1}}, - {{a,loop,3,2},{2,0}}, - {{a,trycatch,1,1},{4,0}}, - {{a,exit_kalle,0,1},{1,0}}]} = cover:analyse(a, coverage, clause), - ?line {ok, [{{a,9},{1,0}}, - {{a,10},{1,0}}, - {{a,11},{1,0}}, - {{a,13},{1,0}}, - {{a,14},{1,0}}, - {{a,15},{1,0}}, - {{a,21},{0,1}}, - {{a,26},{1,0}}, - {{a,31},{1,0}}, - {{a,32},{1,0}}, - {{a,34},{1,0}}, - {{a,36},{0,1}}, - {{a,39},{1,0}}, - {{a,40},{1,0}}, - {{a,44},{1,0}}, - {{a,47},{1,0}}, - {{a,49},{1,0}}, - {{a,51},{1,0}}, - {{a,55},{1,0}}]} = cover:analyse(a, coverage, line), - - ?line {ok, {a,15}} = cover:analyse(a, calls, module), - ?line {ok, [{{a,start,1},1}, - {{a,stop,1},0}, - {{a,pong,1},5}, - {{a,loop,3},6}, - {{a,trycatch,1},2}, - {{a,exit_kalle,0},1}]} = cover:analyse(a, calls, function), - ?line {ok, [{{a,start,1,1},1}, - {{a,stop,1,1},0}, - {{a,pong,1,1},5}, - {{a,loop,3,1},5}, - {{a,loop,3,2},1}, - {{a,trycatch,1,1},2}, - {{a,exit_kalle,0,1},1}]} = cover:analyse(a, calls, clause), - ?line {ok, [{{a,9},1}, - {{a,10},1}, - {{a,11},1}, - {{a,13},1}, - {{a,14},1}, - {{a,15},1}, - {{a,21},0}, - {{a,26},5}, - {{a,31},5}, - {{a,32},5}, - {{a,34},5}, - {{a,36},0}, - {{a,39},1}, - {{a,40},1}, - {{a,44},2}, - {{a,47},1}, - {{a,49},1}, - {{a,51},2}, - {{a,55},1}]} = cover:analyse(a, calls, line), - - ?line {ok, [{{a,start,1},{6,0}}, - {{a,stop,1},{0,1}}, - {{a,pong,1},{1,0}}, - {{a,loop,3},{5,1}}, - {{a,trycatch,1},{4,0}}, - {{a,exit_kalle,0},{1,0}}]} = cover:analyse(a), - ?line {ok, {a,{17,2}}} = cover:analyse(a, module), - ?line {ok, [{{a,start,1},1}, - {{a,stop,1},0}, - {{a,pong,1},5}, - {{a,loop,3},6}, - {{a,trycatch,1},2}, - {{a,exit_kalle,0},1}]} = cover:analyse(a, calls), - - ?line {ok, "a.COVER.out"} = cover:analyse_to_file(a), - ?line {ok, "e.COVER.out"} = cover:analyse_to_file(e), - ?line {ok, "a.COVER.html"} = cover:analyse_to_file(a,[html]), - ?line {ok, "e.COVER.html"} = cover:analyse_to_file(e,[html]), + ok = file:set_cwd(proplists:get_value(data_dir, Config)), + + done = a:start(5), + + {ok, {a,{17,2}}=ACovMod} = cover:analyse(a, coverage, module), + {ok, [{{a,exit_kalle,0},{1,0}}, + {{a,loop,3},{5,1}}, + {{a,pong,1},{1,0}}, + {{a,start,1},{6,0}}, + {{a,stop,1},{0,1}}, + {{a,trycatch,1},{4,0}}]=ACovFunc} = + cover:analyse(a, coverage, function), + {ok, [{{a,exit_kalle,0,1},{1,0}}, + {{a,loop,3,1},{3,1}}, + {{a,loop,3,2},{2,0}}, + {{a,pong,1,1},{1,0}}, + {{a,start,1,1},{6,0}}, + {{a,stop,1,1},{0,1}}, + {{a,trycatch,1,1},{4,0}}]=ACovClause} = + cover:analyse(a, coverage, clause), + {ok, [{{a,9},{1,0}}, + {{a,10},{1,0}}, + {{a,11},{1,0}}, + {{a,13},{1,0}}, + {{a,14},{1,0}}, + {{a,15},{1,0}}, + {{a,21},{0,1}}, + {{a,26},{1,0}}, + {{a,31},{1,0}}, + {{a,32},{1,0}}, + {{a,34},{1,0}}, + {{a,36},{0,1}}, + {{a,39},{1,0}}, + {{a,40},{1,0}}, + {{a,44},{1,0}}, + {{a,47},{1,0}}, + {{a,49},{1,0}}, + {{a,51},{1,0}}, + {{a,55},{1,0}}]=ACovLine} = cover:analyse(a, coverage, line), + + {ok, {a,15}=ACallsMod} = cover:analyse(a, calls, module), + {ok, [{{a,exit_kalle,0},1}, + {{a,loop,3},6}, + {{a,pong,1},5}, + {{a,start,1},1}, + {{a,stop,1},0}, + {{a,trycatch,1},2}]=ACallsFunc} = cover:analyse(a, calls, function), + {ok, [{{a,exit_kalle,0,1},1}, + {{a,loop,3,1},5}, + {{a,loop,3,2},1}, + {{a,pong,1,1},5}, + {{a,start,1,1},1}, + {{a,stop,1,1},0}, + {{a,trycatch,1,1},2}]=ACallsClause} = cover:analyse(a, calls, clause), + {ok, [{{a,9},1}, + {{a,10},1}, + {{a,11},1}, + {{a,13},1}, + {{a,14},1}, + {{a,15},1}, + {{a,21},0}, + {{a,26},5}, + {{a,31},5}, + {{a,32},5}, + {{a,34},5}, + {{a,36},0}, + {{a,39},1}, + {{a,40},1}, + {{a,44},2}, + {{a,47},1}, + {{a,49},1}, + {{a,51},2}, + {{a,55},1}]=ACallsLine} = cover:analyse(a, calls, line), + + {ok,ACovFunc} = cover:analyse(a), + {ok,ACovMod} = cover:analyse(a, module), + {ok,ACallsFunc} = cover:analyse(a, calls), + + {ok, "a.COVER.out"} = cover:analyse_to_file(a), + {ok, "e.COVER.out"} = cover:analyse_to_file(e), + {ok, "a.COVER.html"} = cover:analyse_to_file(a,[html]), + {ok, "e.COVER.html"} = cover:analyse_to_file(e,[html]), + + %% Analyse all modules + Modules = cover:modules(), + N = length(Modules), + + {result,CovFunc,[]} = cover:analyse(), % default = coverage, function + ACovFunc = [A || {{a,_,_},_}=A<-CovFunc], + + {result,CovMod,[]} = cover:analyse(coverage,module), + ACovMod = lists:keyfind(a,1,CovMod), + + {result,CovClause,[]} = cover:analyse(coverage,clause), + ACovClause = [A || {{a,_,_,_},_}=A<-CovClause], + + {result,CovLine,[]} = cover:analyse(coverage,line), + ACovLine = [A || {{a,_},_}=A<-CovLine], + + {result,CallsFunc,[]} = cover:analyse(calls,function), + ACallsFunc = [A || {{a,_,_},_}=A<-CallsFunc], + + {result,CallsMod,[]} = cover:analyse(calls,module), + ACallsMod = lists:keyfind(a,1,CallsMod), + + {result,CallsClause,[]} = cover:analyse(calls,clause), + ACallsClause = [A || {{a,_,_,_},_}=A<-CallsClause], + + {result,CallsLine,[]} = cover:analyse(calls,line), + ACallsLine = [A || {{a,_},_}=A<-CallsLine], + + {result,AllToFile,[]} = cover:analyse_to_file(), + N = length(AllToFile), + true = lists:member("a.COVER.out",AllToFile), + {result,AllToFileHtml,[]} = cover:analyse_to_file([html]), + N = length(AllToFileHtml), + true = lists:member("a.COVER.html",AllToFileHtml), + + %% Analyse list of modules + %% Listing all modules so we can compare result with above result + %% from analysing all. + + {result,CovFunc1,[]} = cover:analyse(Modules), % default = coverage, function + true = lists:sort(CovFunc) == lists:sort(CovFunc1), + + {result,CovMod1,[]} = cover:analyse(Modules,coverage,module), + true = lists:sort(CovMod) == lists:sort(CovMod1), + + {result,CovClause1,[]} = cover:analyse(Modules,coverage,clause), + true = lists:sort(CovClause) == lists:sort(CovClause1), + + {result,CovLine1,[]} = cover:analyse(Modules,coverage,line), + true = lists:sort(CovLine) == lists:sort(CovLine1), + + {result,CallsFunc1,[]} = cover:analyse(Modules,calls,function), + true = lists:sort(CallsFunc1) == lists:sort(CallsFunc1), + + {result,CallsMod1,[]} = cover:analyse(Modules,calls,module), + true = lists:sort(CallsMod) == lists:sort(CallsMod1), + + {result,CallsClause1,[]} = cover:analyse(Modules,calls,clause), + true = lists:sort(CallsClause) == lists:sort(CallsClause1), + + {result,CallsLine1,[]} = cover:analyse(Modules,calls,line), + true = lists:sort(CallsLine) == lists:sort(CallsLine1), + + {result,AllToFile1,[]} = cover:analyse_to_file(Modules), + true = lists:sort(AllToFile) == lists:sort(AllToFile1), + {result,AllToFileHtml1,[]} = cover:analyse_to_file(Modules,[html]), + true = lists:sort(AllToFileHtml) == lists:sort(AllToFileHtml1), %% analyse_to_file of file which is compiled from beam - ?line {ok,f} = compile:file(f,[debug_info]), - ?line code:purge(f), - ?line {module,f} = code:load_file(f), - ?line {ok,f} = cover:compile_beam(f), - ?line f:f2(), - ?line {ok, "f.COVER.out"} = cover:analyse_to_file(f), + {ok,f} = compile:file(f,[debug_info]), + code:purge(f), + {module,f} = code:load_file(f), + {ok,f} = cover:compile_beam(f), + f:f2(), + {ok, "f.COVER.out"} = cover:analyse_to_file(f), %% Source code can be found via source - ?line {ok,v} = compile:file("compile_beam/v",[debug_info]), - ?line code:purge(v), - ?line {module,v} = code:load_file(v), - ?line {ok,v} = cover:compile_beam(v), + {ok,v} = compile:file("compile_beam/v",[debug_info]), + code:purge(v), + {module,v} = code:load_file(v), + {ok,v} = cover:compile_beam(v), {ok,"v.COVER.out"} = cover:analyse_to_file(v), %% Source code cannot be found @@ -348,165 +387,166 @@ analyse(Config) when is_list(Config) -> {module,z} = code:load_file(z), {ok,z} = cover:compile_beam(z), ok = file:delete("z.erl"), - {error,no_source_code_found} = cover:analyse_to_file(z), + {error,{no_source_code_found,z}} = cover:analyse_to_file(z), + {result,[],[{no_source_code_found,z}]} = cover:analyse_to_file([z]), code:purge(z), code:delete(z), - ?line {error,{not_cover_compiled,b}} = cover:analyse(b), - ?line {error,{not_cover_compiled,g}} = cover:analyse(g), - ?line {error,{not_cover_compiled,b}} = cover:analyse_to_file(b), - ?line {error,{not_cover_compiled,g}} = cover:analyse_to_file(g). + {error,{not_cover_compiled,b}} = cover:analyse(b), + {error,{not_cover_compiled,g}} = cover:analyse(g), + {result,[],[{not_cover_compiled,b}]} = cover:analyse([b]), + {error,{not_cover_compiled,b}} = cover:analyse_to_file(b), + {error,{not_cover_compiled,g}} = cover:analyse_to_file(g), + {result,[],[{not_cover_compiled,g}]} = cover:analyse_to_file([g]). -misc(suite) -> []; misc(Config) when is_list(Config) -> - ?line ok = file:set_cwd(?config(data_dir, Config)), + ok = file:set_cwd(proplists:get_value(data_dir, Config)), - ?line [a,cc,crypt,d,e,f,v] = lists:sort(cover:modules()), + [a,cc,crypt,d,e,f,v] = lists:sort(cover:modules()), - ?line {ok,cc} = compile:file(cc), - ?line code:purge(cc), - ?line {module,cc} = code:load_file(cc), - ?line [a,crypt,d,e,f,v] = lists:sort(cover:modules()), + {ok,cc} = compile:file(cc), + code:purge(cc), + {module,cc} = code:load_file(cc), + [a,crypt,d,e,f,v] = lists:sort(cover:modules()), - ?line {file, _File} = cover:is_compiled(a), - ?line false = cover:is_compiled(b), - ?line false = cover:is_compiled(g), + {file, _File} = cover:is_compiled(a), + false = cover:is_compiled(b), + false = cover:is_compiled(g), - ?line ok = cover:reset(a), - ?line {ok, {a,{0,19}}} = cover:analyse(a, module), - ?line ok = cover:reset(). + ok = cover:reset(a), + {ok, {a,{0,19}}} = cover:analyse(a, module), + ok = cover:reset(). -stop(suite) -> []; stop(Config) when is_list(Config) -> - ?line ok = file:set_cwd(?config(data_dir, Config)), - - ?line cover_compiled = code:which(a), - ?line {ok,d} = compile:file(d, [{d,'AGE',42}]), - ?line code:purge(d), - ?line {module,d} = code:load_file(d), - ?line ok = cover:stop(), - ?line Beam = code:which(a), - ?line true = is_unloaded(Beam), - - ?line Files = lsfiles(), - ?line remove(files(Files, ".out")), - ?line remove(files(Files, ".html")), - ?line remove(files(Files, ".beam")). - -distribution(suite) -> []; + ok = file:set_cwd(proplists:get_value(data_dir, Config)), + + cover_compiled = code:which(a), + {ok,d} = compile:file(d, [{d,'AGE',42}]), + code:purge(d), + {module,d} = code:load_file(d), + ok = cover:stop(), + Beam = code:which(a), + true = is_unloaded(Beam), + + Files = lsfiles(), + remove(files(Files, ".out")), + remove(files(Files, ".html")), + remove(files(Files, ".beam")). + distribution(Config) when is_list(Config) -> - ?line DataDir = ?config(data_dir, Config), - ?line ok = file:set_cwd(DataDir), + DataDir = proplists:get_value(data_dir, Config), + ok = file:set_cwd(DataDir), - ?line {ok,N1} = ?t:start_node(cover_SUITE_distribution1,slave,[]), - ?line {ok,N2} = ?t:start_node(cover_SUITE_distribution2,slave,[]), - ?line {ok,N3} = ?t:start_node(cover_SUITE_distribution3,slave,[]), - ?line {ok,N4} = ?t:start_node(cover_SUITE_distribution4,slave,[]), + {ok,N1} = test_server:start_node(cover_SUITE_distribution1,slave,[]), + {ok,N2} = test_server:start_node(cover_SUITE_distribution2,slave,[]), + {ok,N3} = test_server:start_node(cover_SUITE_distribution3,slave,[]), + {ok,N4} = test_server:start_node(cover_SUITE_distribution4,slave,[]), %% Check that an already compiled module is loaded on new nodes - ?line {ok,f} = cover:compile(f), - ?line {ok,[_,_,_,_]} = cover:start(nodes()), - ?line cover_compiled = code:which(f), - ?line cover_compiled = rpc:call(N1,code,which,[f]), - ?line cover_compiled = rpc:call(N2,code,which,[f]), - ?line cover_compiled = rpc:call(N3,code,which,[f]), - ?line cover_compiled = rpc:call(N4,code,which,[f]), + {ok,f} = cover:compile(f), + {ok,[_,_,_,_]} = cover:start(nodes()), + cover_compiled = code:which(f), + cover_compiled = rpc:call(N1,code,which,[f]), + cover_compiled = rpc:call(N2,code,which,[f]), + cover_compiled = rpc:call(N3,code,which,[f]), + cover_compiled = rpc:call(N4,code,which,[f]), %% Check that a node cannot be started twice - ?line {ok,[]} = cover:start(N2), + {ok,[]} = cover:start(N2), %% Check that the current node (i.e. the main node) is not started with %% start/1 and not stopped with stop/1 - ?line {ok,[]} = cover:start(node()), - ?line ok = cover:stop(node()), - ?line true = is_pid(whereis(cover_server)), + {ok,[]} = cover:start(node()), + ok = cover:stop(node()), + true = is_pid(whereis(cover_server)), %% Check that a new compiled module is loaded on all existing nodes - ?line compile:file("compile_beam/v",[debug_info]), - ?line {ok,v} = cover:compile_beam(v), - ?line cover_compiled = code:which(v), - ?line cover_compiled = rpc:call(N1,code,which,[v]), - ?line cover_compiled = rpc:call(N2,code,which,[v]), - ?line cover_compiled = rpc:call(N3,code,which,[v]), - ?line cover_compiled = rpc:call(N4,code,which,[v]), - + compile:file("compile_beam/v",[debug_info]), + {ok,v} = cover:compile_beam(v), + cover_compiled = code:which(v), + cover_compiled = rpc:call(N1,code,which,[v]), + cover_compiled = rpc:call(N2,code,which,[v]), + cover_compiled = rpc:call(N3,code,which,[v]), + cover_compiled = rpc:call(N4,code,which,[v]), + %% this is lost when the node is killed - ?line rpc:call(N3,f,f2,[]), - ?line rpc:call(N3,erlang,halt,[]), + rpc:call(N3,f,f2,[]), + rpc:call(N3,erlang,halt,[]), %% this should be visible in analyse - ?line rpc:call(N1,f,f1,[]), + rpc:call(N1,f,f1,[]), %% Check that data is collected from remote node when stopped - ?line ok = cover:stop(N1), - ?line N1Beam = rpc:call(N1,code,which,[f]), - ?line true = is_unloaded(N1Beam), - ?line check_f_calls(1,0), + ok = cover:stop(N1), + N1Beam = rpc:call(N1,code,which,[f]), + true = is_unloaded(N1Beam), + check_f_calls(1,0), %% Call f:f1() again on another node and check that number of calls is %% accumulated. - ?line f:f1(), - ?line check_f_calls(2,0), - + f:f1(), + check_f_calls(2,0), + %% Check that reset works on all nodes - ?line f:f1(), - ?line rpc:call(N2,f,f1,[]), - ?line ok = cover:reset(f), - ?line check_f_calls(0,0), - + f:f1(), + rpc:call(N2,f,f1,[]), + ok = cover:reset(f), + check_f_calls(0,0), + %% Check that data is collected from all nodes - ?line rpc:call(N2,f,f1,[]), - ?line f:f2(), - ?line check_f_calls(1,1), + rpc:call(N2,f,f1,[]), + f:f2(), + check_f_calls(1,1), %% Check that same data is not fetched again (i.e. that analyse does %% reset on the remote node(s)) - ?line check_f_calls(1,1), + check_f_calls(1,1), %% Another checn that data is not fetched twice, i.e. when flushed %% then analyse should not add the same data again. - ?line rpc:call(N4,f,f2,[]), - ?line ok = cover:flush(N4), - ?line check_f_calls(1,2), + rpc:call(N4,f,f2,[]), + ok = cover:flush(N4), + check_f_calls(1,2), %% Check that flush collects data so calls are not lost if node is killed - ?line rpc:call(N4,f,f2,[]), - ?line ok = cover:flush(N4), - ?line rpc:call(N4,erlang,halt,[]), - ?line check_f_calls(1,3), + rpc:call(N4,f,f2,[]), + ok = cover:flush(N4), + rpc:call(N4,erlang,halt,[]), + check_f_calls(1,3), %% Check that stop() unloads on all nodes - ?line ok = cover:stop(), - ?line timer:sleep(100), %% Give nodes time to unload on slow machines. - ?line LocalBeam = code:which(f), - ?line N2Beam = rpc:call(N2,code,which,[f]), - ?line true = is_unloaded(LocalBeam), - ?line true = is_unloaded(N2Beam), + ok = cover:stop(), + timer:sleep(100), %% Give nodes time to unload on slow machines. + LocalBeam = code:which(f), + N2Beam = rpc:call(N2,code,which,[f]), + true = is_unloaded(LocalBeam), + true = is_unloaded(N2Beam), %% Check that cover_server on remote node does not die if main node dies - ?line {ok,[N1]} = cover:start(N1), - ?line true = is_pid(N1Server = rpc:call(N1,erlang,whereis,[cover_server])), - ?line exit(whereis(cover_server),kill), - ?line timer:sleep(100), - ?line N1Server = rpc:call(N1,erlang,whereis,[cover_server]), + {ok,[N1]} = cover:start(N1), + true = is_pid(N1Server = rpc:call(N1,erlang,whereis,[cover_server])), + exit(whereis(cover_server),kill), + timer:sleep(100), + N1Server = rpc:call(N1,erlang,whereis,[cover_server]), %% Cleanup - ?line Files = lsfiles(), - ?line remove(files(Files, ".beam")), - ?line ?t:stop_node(N1), - ?line ?t:stop_node(N2). + Files = lsfiles(), + remove(files(Files, ".beam")), + test_server:stop_node(N1), + test_server:stop_node(N2). %% Test that a lost node is reconnected reconnect(Config) -> - DataDir = ?config(data_dir, Config), + DataDir = proplists:get_value(data_dir, Config), ok = file:set_cwd(DataDir), {ok,a} = compile:file(a), {ok,b} = compile:file(b), {ok,f} = compile:file(f), - {ok,N1} = ?t:start_node(cover_SUITE_reconnect,peer, - [{args," -pa " ++ DataDir},{start_cover,false}]), + {ok,N1} = test_server:start_node(cover_SUITE_reconnect,peer, + [{args," -pa " ++ DataDir}, + {start_cover,false}]), {ok,a} = cover:compile(a), {ok,f} = cover:compile(f), {ok,[N1]} = cover:start(nodes()), @@ -547,19 +587,20 @@ reconnect(Config) -> check_f_calls(2,1), cover:stop(), - ?t:stop_node(N1), + test_server:stop_node(N1), ok. %% Test that a lost node is reconnected - also if it has been dead die_and_reconnect(Config) -> - DataDir = ?config(data_dir, Config), + DataDir = proplists:get_value(data_dir, Config), ok = file:set_cwd(DataDir), {ok,f} = compile:file(f), NodeName = cover_SUITE_die_and_reconnect, - {ok,N1} = ?t:start_node(NodeName,peer, - [{args," -pa " ++ DataDir},{start_cover,false}]), + {ok,N1} = test_server:start_node(NodeName,peer, + [{args," -pa " ++ DataDir}, + {start_cover,false}]), %% {ok,a} = cover:compile(a), {ok,f} = cover:compile(f), {ok,[N1]} = cover:start(nodes()), @@ -576,8 +617,9 @@ die_and_reconnect(Config) -> check_f_calls(1,0), % only the first call - before the flush %% Restart the node and check that cover reconnects - {ok,N1} = ?t:start_node(NodeName,peer, - [{args," -pa " ++ DataDir},{start_cover,false}]), + {ok,N1} = test_server:start_node(NodeName,peer, + [{args," -pa " ++ DataDir}, + {start_cover,false}]), timer:sleep(100), [N1] = cover:which_nodes(), % we are reconnected cover_compiled = rpc:call(N1,code,which,[f]), @@ -589,20 +631,21 @@ die_and_reconnect(Config) -> check_f_calls(2,0), cover:stop(), - ?t:stop_node(N1), + test_server:stop_node(N1), ok. %% Test that a stopped node is not marked as lost, i.e. that it is not %% reconnected if it is restarted (OTP-10638) dont_reconnect_after_stop(Config) -> - DataDir = ?config(data_dir, Config), + DataDir = proplists:get_value(data_dir, Config), ok = file:set_cwd(DataDir), {ok,f} = compile:file(f), NodeName = cover_SUITE_dont_reconnect_after_stop, - {ok,N1} = ?t:start_node(NodeName,peer, - [{args," -pa " ++ DataDir},{start_cover,false}]), + {ok,N1} = test_server:start_node(NodeName,peer, + [{args," -pa " ++ DataDir}, + {start_cover,false}]), {ok,f} = cover:compile(f), {ok,[N1]} = cover:start(nodes()), @@ -617,8 +660,9 @@ dont_reconnect_after_stop(Config) -> check_f_calls(1,0), %% Restart the node and check that cover does not reconnect - {ok,N1} = ?t:start_node(NodeName,peer, - [{args," -pa " ++ DataDir},{start_cover,false}]), + {ok,N1} = test_server:start_node(NodeName,peer, + [{args," -pa " ++ DataDir}, + {start_cover,false}]), timer:sleep(300), cover_which_nodes([]), Beam = rpc:call(N1,code,which,[f]), @@ -632,20 +676,21 @@ dont_reconnect_after_stop(Config) -> check_f_calls(1,0), cover:stop(), - ?t:stop_node(N1), + test_server:stop_node(N1), ok. %% Test that a node which is stopped while it is marked as lost is not %% reconnected if it is restarted (OTP-10638) stop_node_after_disconnect(Config) -> - DataDir = ?config(data_dir, Config), + DataDir = proplists:get_value(data_dir, Config), ok = file:set_cwd(DataDir), {ok,f} = compile:file(f), NodeName = cover_SUITE_stop_node_after_disconnect, - {ok,N1} = ?t:start_node(NodeName,peer, - [{args," -pa " ++ DataDir},{start_cover,false}]), + {ok,N1} = test_server:start_node(NodeName,peer, + [{args," -pa " ++ DataDir}, + {start_cover,false}]), {ok,f} = cover:compile(f), {ok,[N1]} = cover:start(nodes()), @@ -662,8 +707,9 @@ stop_node_after_disconnect(Config) -> cover:stop(N1), %% Restart the node and check that cover does not reconnect - {ok,N1} = ?t:start_node(NodeName,peer, - [{args," -pa " ++ DataDir},{start_cover,false}]), + {ok,N1} = test_server:start_node(NodeName,peer, + [{args," -pa " ++ DataDir}, + {start_cover,false}]), timer:sleep(300), cover_which_nodes([]), Beam = rpc:call(N1,code,which,[f]), @@ -677,145 +723,249 @@ stop_node_after_disconnect(Config) -> check_f_calls(1,0), cover:stop(), - ?t:stop_node(N1), + test_server:stop_node(N1), + ok. + +distribution_performance(Config) -> + PrivDir = proplists:get_value(priv_dir,Config), + Dir = filename:join(PrivDir,"distribution_performance"), + AllFiles = filename:join(Dir,"*"), + ok = filelib:ensure_dir(AllFiles), + code:add_patha(Dir), + M = 9, % Generate M modules + F = 210, % with F functions + C = 10, % and each function of C clauses + Mods = generate_modules(M,F,C,Dir), + + % test_server:break(""), + + NodeName = cover_SUITE_distribution_performance, + {ok,N1} = test_server:start_node(NodeName,peer,[{start_cover,false}]), + %% CFun = fun() -> + %% [{ok,_} = cover:compile_beam(Mod) || Mod <- Mods] + %% end, + CFun = fun() -> cover:compile_beam(Mods) end, + {CT,_CA} = timer:tc(CFun), + % erlang:display(_CA), + erlang:display({compile,CT}), + + {SNT,_} = timer:tc(fun() -> {ok,[N1]} = cover:start(nodes()) end), + erlang:display({start_node,SNT}), + + [1 = rpc:call(N1,Mod,f1,[1]) || Mod <- Mods], + + % Fun = fun() -> [cover:analyse(Mod,calls,function) || Mod<-Mods] end, + % Fun = fun() -> analyse_all(Mods,calls,function) end, + % Fun = fun() -> cover:analyse('_',calls,function) end, + Fun = fun() -> cover:analyse(Mods,calls,function) end, + + % Fun = fun() -> [begin cover:analyse_to_file(Mod,[html]) end || Mod<-Mods] end, + % Fun = fun() -> analyse_all_to_file(Mods,[html]) end, + % Fun = fun() -> cover:analyse_to_file(Mods,[html]) end, + % Fun = fun() -> cover:analyse_to_file([html]) end, + + % Fun = fun() -> cover:reset() end, + + {AT,_A} = timer:tc(Fun), + erlang:display({analyse,AT}), + % erlang:display(lists:sort([X || X={_MFA,N} <- lists:append([L || {ok,L}<-A]), N=/=0])), + + %% fprof:apply(Fun, [],[{procs,[whereis(cover_server)]}]), + %% fprof:profile(), + %% fprof:analyse(dest,[]), + + {SNT2,_} = timer:tc(fun() -> test_server:stop_node(N1) end), + erlang:display({stop_node,SNT2}), + + code:del_path(Dir), + Files = filelib:wildcard(AllFiles), + [ok = file:delete(File) || File <- Files], + ok = file:del_dir(Dir), ok. -export_import(suite) -> []; +%% Run analysis in parallel +analyse_all(Mods,Analysis,Level) -> + Pids = [begin + Pid = spawn(fun() -> + {ok,A} = cover:analyse(Mod,Analysis,Level), + exit(A) + end), + erlang:monitor(process,Pid), + Pid + end || Mod <- Mods], + get_downs(Pids,[]). + +analyse_all_to_file(Mods,Opts) -> + Pids = [begin + Pid = cover:async_analyse_to_file(Mod,Opts), + erlang:monitor(process,Pid), + Pid + end || Mod <- Mods], + get_downs(Pids,[]). + +get_downs([],Acc) -> + Acc; +get_downs(Pids,Acc) -> + receive + {'DOWN', _Ref, _Type, Pid, A} -> + get_downs(lists:delete(Pid,Pids),[A|Acc]) + end. + +generate_modules(0,_,_,_) -> + []; +generate_modules(M,F,C,Dir) -> + ModStr = "m" ++ integer_to_list(M), + Mod = list_to_atom(ModStr), + Src = ["-module(",ModStr,").\n" + "-compile(export_all).\n" | + generate_functions(F,C)], + Erl = filename:join(Dir,ModStr++".erl"), + ok = file:write_file(Erl,Src), + {ok,Mod} = compile:file(Erl,[{outdir,Dir},debug_info,report]), + [Mod | generate_modules(M-1,F,C,Dir)]. + +generate_functions(0,_) -> + []; +generate_functions(F,C) -> + Func = "f" ++ integer_to_list(F), + [generate_clauses(C,Func) | generate_functions(F-1,C)]. + +generate_clauses(0,_) -> + []; +generate_clauses(C,Func) -> + CStr = integer_to_list(C), + Sep = if C==1 -> "."; true -> ";" end, + [Func,"(",CStr,") -> ",CStr,Sep,"\n" | + generate_clauses(C-1,Func)]. + + export_import(Config) when is_list(Config) -> - ?line DataDir = ?config(data_dir, Config), - ?line ok = file:set_cwd(DataDir), - ?line PortCount = length(erlang:ports()), + DataDir = proplists:get_value(data_dir, Config), + ok = file:set_cwd(DataDir), + PortCount = length(erlang:ports()), %% Export one module - ?line {ok,f} = cover:compile(f), - ?line f:f1(), + {ok,f} = cover:compile(f), + f:f1(), %% check that no info is written about where data comes from when no %% files are imported - ?line ?t:capture_start(), - ?line check_f_calls(1,0), - ?line [] = ?t:capture_get(), - ?line ?t:capture_stop(), - ?line ok = cover:export("f_exported",f), - ?line check_f_calls(1,0), - ?line ok = cover:stop(), - + test_server:capture_start(), + check_f_calls(1,0), + [] = test_server:capture_get(), + test_server:capture_stop(), + ok = cover:export("f_exported",f), + check_f_calls(1,0), + ok = cover:stop(), + %% Check that same data exists after import and that info is written about %% data comming from imported file - ?line ok = cover:import("f_exported"), - ?line ?t:capture_start(), - ?line check_f_calls(1,0), - ?line [Text1] = ?t:capture_get(), - ?line "Analysis includes data from imported files"++_ = lists:flatten(Text1), - ?line ?t:capture_stop(), + ok = cover:import("f_exported"), + test_server:capture_start(), + check_f_calls(1,0), + [Text1] = test_server:capture_get(), + "Analysis includes data from imported files"++_ = lists:flatten(Text1), + test_server:capture_stop(), %% Export all modules - ?line {ok,a} = cover:compile(a), - ?line ?t:capture_start(), - ?line ok = cover:export("all_exported"), - ?line [] = ?t:capture_get(), -% ?line "Export includes data from imported files"++_ = lists:flatten(Text2), - ?line ?t:capture_stop(), - ?line ok = cover:stop(), - ?line ok = cover:import("all_exported"), - ?line check_f_calls(1,0), + {ok,a} = cover:compile(a), + test_server:capture_start(), + ok = cover:export("all_exported"), + [] = test_server:capture_get(), + % "Export includes data from imported files"++_ = lists:flatten(Text2), + test_server:capture_stop(), + ok = cover:stop(), + ok = cover:import("all_exported"), + check_f_calls(1,0), %% Check that data is reset when module is compiled again, and that %% warning is written when data is deleted for imported module. - ?line ?t:capture_start(), - ?line {ok,f} = cover:compile(f), - ?line timer:sleep(10), % capture needs some time - ?line [Text3] = ?t:capture_get(), - ?line "WARNING: Deleting data for module f imported from" ++ _ = - lists:flatten(Text3), - ?line ?t:capture_stop(), - ?line check_f_calls(0,0), - + test_server:capture_start(), + {ok,f} = cover:compile(f), + timer:sleep(10), % capture needs some time + [Text3] = test_server:capture_get(), + "WARNING: Deleting data for module f imported from" ++ _ = lists:flatten(Text3), + test_server:capture_stop(), + check_f_calls(0,0), + %% Check that data is summed up when first compiled and then imported %% The module which has been compiled (f) is loaded from the file %% all_exported again (since it has been reset during cover compiling), %% but the other module (a) is not loaded since it is already loaded - ?line f:f1(), - ?line f:f2(), - ?line ok = cover:import("f_exported"), - ?line ?t:capture_start(), - ?line ok = cover:import("all_exported"), - ?line [Text4] = ?t:capture_get(), % a is not loaded again - ?line "WARNING: Module a already imported from " ++ _ = lists:flatten(Text4), - ?line ?t:capture_stop(), - ?line check_f_calls(3,1), + f:f1(), + f:f2(), + ok = cover:import("f_exported"), + test_server:capture_start(), + ok = cover:import("all_exported"), + [Text4] = test_server:capture_get(), % a is not loaded again + "WARNING: Module a already imported from " ++ _ = lists:flatten(Text4), + test_server:capture_stop(), + check_f_calls(3,1), %% Check that warning is written when same file is imported twice, %% and that data is not imported again - ?line ?t:capture_start(), - ?line ok = cover:import("all_exported"), - ?line [Text5,Text6] = ?t:capture_get(), - ?line "WARNING: Module f already imported from " ++ _ = lists:flatten(Text5), - ?line "WARNING: Module a already imported from " ++ _ = lists:flatten(Text6), - ?line ?t:capture_stop(), - ?line check_f_calls(3,1), + test_server:capture_start(), + ok = cover:import("all_exported"), + [Text5,Text6] = test_server:capture_get(), + "WARNING: Module f already imported from " ++ _ = lists:flatten(Text5), + "WARNING: Module a already imported from " ++ _ = lists:flatten(Text6), + test_server:capture_stop(), + check_f_calls(3,1), %% Check that reset removes all data and that the file which has been %% reset can be imported again with no warning - ?line cover:reset(f), - ?line check_f_calls(0,0), - ?line ?t:capture_start(), - ?line ok = cover:import("all_exported"), - ?line [Text7] = ?t:capture_get(), % warning only on mod a - ?line "WARNING: Module a already imported from " ++ _ = lists:flatten(Text7), - ?line ?t:capture_stop(), - ?line check_f_calls(1,0), + cover:reset(f), + check_f_calls(0,0), + test_server:capture_start(), + ok = cover:import("all_exported"), + [Text7] = test_server:capture_get(), % warning only on mod a + "WARNING: Module a already imported from " ++ _ = lists:flatten(Text7), + test_server:capture_stop(), + check_f_calls(1,0), %% same as above - only reset all - ?line cover:reset(), - ?line check_f_calls(0,0), - ?line ?t:capture_start(), - ?line ok = cover:import("all_exported"), - ?line [] = ?t:capture_get(), % no warnings - ?line ?t:capture_stop(), - ?line check_f_calls(1,0), + cover:reset(), + check_f_calls(0,0), + test_server:capture_start(), + ok = cover:import("all_exported"), + [] = test_server:capture_get(), % no warnings + test_server:capture_stop(), + check_f_calls(1,0), %% Check no raw files are left open - ?line PortCount = length(erlang:ports()), + PortCount = length(erlang:ports()), %% Cleanup - ?line ok = cover:stop(), - ?line Files = lsfiles(), - ?line remove(["f_exported","all_exported"|files(Files, ".beam")]). + ok = cover:stop(), + Files = lsfiles(), + remove(["f_exported","all_exported"|files(Files, ".beam")]). -otp_5031(suite) -> []; otp_5031(Config) when is_list(Config) -> + ct:timetrap({seconds, 10}), - Dog = ?t:timetrap(?t:seconds(10)), - - ?line {ok,N1} = ?t:start_node(cover_SUITE_distribution1,slave,[]), - ?line {ok,[N1]} = cover:start(N1), - ?line {error,not_main_node} = rpc:call(N1,cover,modules,[]), - ?line cover:stop(), - - ?t:timetrap_cancel(Dog), + {ok,N1} = test_server:start_node(cover_SUITE_otp_5031,slave,[]), + {ok,[N1]} = cover:start(N1), + {error,not_main_node} = rpc:call(N1,cover,modules,[]), + cover:stop(), + test_server:stop_node(N1), ok. -eif(doc) -> - ["Test the \'Exclude Included Functions\' functionality"]; -eif(suite) -> - []; +%% Test the \'Exclude Included Functions\' functionality eif(Config) when is_list(Config) -> - ?line ok = file:set_cwd(filename:join(?config(data_dir, Config), - "included_functions")), - ?line {ok, cover_inc} = compile:file(cover_inc,[debug_info]), - ?line {ok, cover_inc} = cover:compile_beam(cover_inc), + ok = file:set_cwd(filename:join(proplists:get_value(data_dir, Config), + "included_functions")), + {ok, cover_inc} = compile:file(cover_inc,[debug_info]), + {ok, cover_inc} = cover:compile_beam(cover_inc), %% This function will cause an included function to be executed. %% The analysis should only show the lines that actually exist %% in cover_inc.beam - not the ones from the included file. - ?line cover_inc:func(), - ?line {ok, [_, _]} = cover:analyse(cover_inc, line), + cover_inc:func(), + {ok, [_, _]} = cover:analyse(cover_inc, line), ok. - -otp_5305(suite) -> []; + otp_5305(Config) when is_list(Config) -> - ?line ok = file:set_cwd(?config(priv_dir, Config)), + ok = file:set_cwd(proplists:get_value(priv_dir, Config)), File = "t.erl", Test = <<"-module(t). @@ -824,35 +974,32 @@ otp_5305(Config) when is_list(Config) -> t() -> ets:fun2ms(fun(X) -> X end). ">>, - ?line ok = file:write_file(File, Test), - ?line {ok, t} = cover:compile(File), - ?line ok = file:delete(File), - + ok = file:write_file(File, Test), + {ok, t} = cover:compile(File), + ok = file:delete(File), ok. -otp_5418(suite) -> []; otp_5418(Config) when is_list(Config) -> - ?line ok = file:set_cwd(?config(priv_dir, Config)), + ok = file:set_cwd(proplists:get_value(priv_dir, Config)), File = "t.erl", Test = <<"-module(t). ">>, - ?line ok = file:write_file(File, Test), - ?line {ok, t} = cover:compile(File), - ?line {ok,{t,{0,0}}} = cover:analyse(t, module), - ?line ok = file:delete(File), - + ok = file:write_file(File, Test), + {ok, t} = cover:compile(File), + {ok,{t,{0,0}}} = cover:analyse(t, module), + ok = file:delete(File), ok. otp_6115(Config) when is_list(Config) -> - ?line {ok, CWD} = file:get_cwd(), - ?line Dir = filename:join(?config(data_dir, Config), otp_6115), - ?line ok = file:set_cwd(Dir), - ?line {ok, f1} = compile:file(f1, [debug_info]), - ?line {ok, f2} = compile:file(f2, [debug_info]), + {ok, CWD} = file:get_cwd(), + Dir = filename:join(proplists:get_value(data_dir, Config), otp_6115), + ok = file:set_cwd(Dir), + {ok, f1} = compile:file(f1, [debug_info]), + {ok, f2} = compile:file(f2, [debug_info]), %% Cover compile f1, but not f2 - ?line {ok, f1} = cover:compile(f1), + {ok, f1} = cover:compile(f1), %% If f1 is cover compiled, a process P is started with a %% reference to the fun created in start_fail/0, and cover:stop() is @@ -866,39 +1013,37 @@ otp_6115(Config) when is_list(Config) -> Pid2 = f1:start_b(), %% Now stop cover - ?line cover:stop(), - + cover:stop(), + %% Ensure that f1 is loaded (and not cover compiled), and that %% both Pid1 and Pid2 are dead. case code:which(f1) of - Beam when is_list(Beam) -> - ok; - Other -> - ?line ?t:fail({"f1 is not reloaded", Other}) + Beam when is_list(Beam) -> + ok; + Other -> + ct:fail({"f1 is not reloaded", Other}) end, case process_info(Pid1) of - undefined -> - ok; - _PI1 -> - RefToOldP1 = erlang:check_process_code(Pid1, f1), - ?t:fail({"Pid1 still alive", RefToOldP1}) + undefined -> + ok; + _PI1 -> + RefToOldP1 = erlang:check_process_code(Pid1, f1), + ct:fail({"Pid1 still alive", RefToOldP1}) end, case process_info(Pid2) of - undefined -> - ok; - _PI2 -> - RefToOldP2 = erlang:check_process_code(Pid1, f2), - ?t:fail({"Pid2 still alive", RefToOldP2}) + undefined -> + ok; + _PI2 -> + RefToOldP2 = erlang:check_process_code(Pid1, f2), + ct:fail({"Pid2 still alive", RefToOldP2}) end, - ?line file:set_cwd(CWD), + file:set_cwd(CWD), ok. -otp_7095(doc) -> - ["andalso/orelse"]; -otp_7095(suite) -> []; +%% andalso/orelse otp_7095(Config) when is_list(Config) -> - ?line ok = file:set_cwd(?config(priv_dir, Config)), + ok = file:set_cwd(proplists:get_value(priv_dir, Config)), File = "t.erl", Test = <<"-module(t). @@ -984,88 +1129,84 @@ otp_7095(Config) when is_list(Config) -> add_one(T) -> put(T, get(T) + 1). % 82 ">>, - ?line ok = file:write_file(File, Test), - ?line {ok, t} = cover:compile(File), - ?line ok = t:t(), - ?line {ok,[{{t,4},1},{{t,5},1},{{t,6},1},{{t,7},1},{{t,8},1},{{t,9},1}, - {{t,10},1},{{t,11},1},{{t,12},1},{{t,13},1},{{t,14},1}, - {{t,15},1},{{t,16},1},{{t,17},1}, - {{t,20},1},{{t,22},0}, - {{t,25},1},{{t,27},1}, - {{t,30},1},{{t,32},1}, - {{t,35},1},{{t,37},0}, - {{t,40},1},{{t,42},1},{{t,44},1}, - {{t,47},1},{{t,48},1}, - {{t,51},1},{{t,53},1},{{t,55},0}, - {{t,58},1},{{t,60},1},{{t,62},1},{{t,64},0}, - {{t,67},1},{{t,69},1},{{t,71},1},{{t,74},1}, - {{t,76},0},{{t,78},1}, - {{t,82},2}]} = cover:analyse(t, calls, line), - ?line ok = file:delete(File), - + ok = file:write_file(File, Test), + {ok, t} = cover:compile(File), + ok = t:t(), + {ok,[{{t,4},1},{{t,5},1},{{t,6},1},{{t,7},1},{{t,8},1},{{t,9},1}, + {{t,10},1},{{t,11},1},{{t,12},1},{{t,13},1},{{t,14},1}, + {{t,15},1},{{t,16},1},{{t,17},1}, + {{t,20},1},{{t,22},0}, + {{t,25},1},{{t,27},1}, + {{t,30},1},{{t,32},1}, + {{t,35},1},{{t,37},0}, + {{t,40},1},{{t,42},1},{{t,44},1}, + {{t,47},1},{{t,48},1}, + {{t,51},1},{{t,53},1},{{t,55},0}, + {{t,58},1},{{t,60},1},{{t,62},1},{{t,64},0}, + {{t,67},1},{{t,69},1},{{t,71},1},{{t,74},1}, + {{t,76},0},{{t,78},1}, + {{t,82},2}]} = cover:analyse(t, calls, line), + ok = file:delete(File), ok. -otp_8270(doc) -> - ["OTP-8270. Bug."]; -otp_8270(suite) -> []; + +%% OTP-8270. Bug. otp_8270(Config) when is_list(Config) -> - ?line DataDir = ?config(data_dir, Config), - ?line ok = file:set_cwd(DataDir), + DataDir = proplists:get_value(data_dir, Config), + ok = file:set_cwd(DataDir), - ?line PrivDir = ?config(priv_dir, Config), + PrivDir = proplists:get_value(priv_dir, Config), As = [{args," -pa " ++ PrivDir}], - ?line {ok,N1} = ?t:start_node(cover_n1,slave,As), - ?line {ok,N2} = ?t:start_node(cover_n2,slave,As), - ?line {ok,N3} = ?t:start_node(cover_n3,slave,As), - + {ok,N1} = test_server:start_node(cover_n1,slave,As), + {ok,N2} = test_server:start_node(cover_n2,slave,As), + {ok,N3} = test_server:start_node(cover_n3,slave,As), + timer:sleep(500), - cover:start(nodes()), - - Test = << - "-module(m).\n" - "-compile(export_all).\n" - "t() -> t(0).\n" - "l() ->\n" - " catch ets:tab2list(cover_internal_data_table).\n" - "t(Sz) ->\n" - " case ets:info(cover_internal_data_table, size) of\n" - " Sz ->\n" - " m:t(Sz); % Not a local call! Newly loaded code is entered.\n" - " NSz ->\n" - " % error_logger:info_msg(\"~p: ~p ~p change~n L1 ~p~n\", \n" - " % [node(), Sz, NSz, l()]),\n" - " m:t(NSz)\n" - " end.\n">>, - ?line _File = c_mod(m, Test, Config), + {ok,[_,_,_]} = cover:start(nodes()), + + Test = <<"-module(m).\n" + "-compile(export_all).\n" + "t() -> t(0).\n" + "l() ->\n" + " catch ets:tab2list(cover_internal_data_table).\n" + "t(Sz) ->\n" + " case ets:info(cover_internal_data_table, size) of\n" + " Sz ->\n" + " m:t(Sz); % Not a local call! Newly loaded code is entered.\n" + " NSz ->\n" + " % error_logger:info_msg(\"~p: ~p ~p change~n L1 ~p~n\", \n" + " % [node(), Sz, NSz, l()]),\n" + " m:t(NSz)\n" + " end.\n">>, + _File = c_mod(m, Test, Config), Fun = fun m:t/0, - ?line Pid1 = spawn(Fun), - ?line Pid2 = spawn(N1, Fun), - ?line Pid3 = spawn(N2, Fun), - ?line Pid4 = spawn(N3, Fun), + Pid1 = spawn(Fun), + Pid2 = spawn(N1, Fun), + Pid3 = spawn(N2, Fun), + Pid4 = spawn(N3, Fun), - ?line {ok, m} = cover:compile_beam(m), + {ok, m} = cover:compile_beam(m), timer:sleep(1000), - ?line Info = erlang:process_info(Pid1), - ?line N1_info = rpc:call(N1, erlang, process_info, [Pid2]), - ?line N2_info = rpc:call(N2, erlang, process_info, [Pid3]), - ?line N3_info = rpc:call(N3, erlang, process_info, [Pid4]), + Info = erlang:process_info(Pid1), + N1_info = rpc:call(N1, erlang, process_info, [Pid2]), + N2_info = rpc:call(N2, erlang, process_info, [Pid3]), + N3_info = rpc:call(N3, erlang, process_info, [Pid4]), - ?line true = is_list(Info), - ?line {N1,true} = {N1,is_list(N1_info)}, - ?line {N2,true} = {N2,is_list(N2_info)}, - ?line {N3,true} = {N3,is_list(N3_info)}, + true = is_list(Info), + {N1,true} = {N1,is_list(N1_info)}, + {N2,true} = {N2,is_list(N2_info)}, + {N3,true} = {N3,is_list(N3_info)}, - ?line ?t:stop_node(N1), - ?line ?t:stop_node(N2), - ?line ?t:stop_node(N3), + exit(Pid1,kill), + test_server:stop_node(N1), + test_server:stop_node(N2), + test_server:stop_node(N3), ok. -otp_8273(doc) -> - ["OTP-8273. Bug."]; -otp_8273(suite) -> []; +%% OTP-8273. Bug. otp_8273(Config) when is_list(Config) -> Test = <<"-module(t). -export([t/0]). @@ -1074,27 +1215,22 @@ otp_8273(Config) when is_list(Config) -> bar = false orelse bar, ok. ">>, - ?line File = cc_mod(t, Test, Config), - ?line ok = t:t(), - ?line ok = file:delete(File), + File = cc_mod(t, Test, Config), + ok = t:t(), + ok = file:delete(File), ok. -otp_8340(doc) -> - ["OTP-8340. Bug."]; -otp_8340(suite) -> []; +%% OTP-8340. Bug. otp_8340(Config) when is_list(Config) -> - ?line [{{t,1},1},{{t,2},1},{{t,4},1}] = - analyse_expr(<<"<< \n" - " <<3:2, \n" - " SeqId:62>> \n" - " || SeqId <- [64] >>">>, Config), - + [{{t,1},1},{{t,2},1},{{t,4},1}] = + analyse_expr(<<"<< \n" + " <<3:2, \n" + " SeqId:62>> \n" + " || SeqId <- [64] >>">>, Config), ok. -otp_8188(doc) -> - ["Clauses on the same line."]; -otp_8188(suite) -> []; +%% Clauses on the same line. otp_8188(Config) when is_list(Config) -> %% This example covers the bug report: Test = <<"-module(t). @@ -1110,10 +1246,10 @@ otp_8188(Config) when is_list(Config) -> _Res = ?FOOBAR(X). ">>, - ?line File = cc_mod(t, Test, Config), - ?line false = t:test(nok), - ?line {ok,[{{t,11},1},{{t,12},1}]} = cover:analyse(t, calls, line), - ?line ok = file:delete(File), + File = cc_mod(t, Test, Config), + false = t:test(nok), + {ok,[{{t,11},1},{{t,12},1}]} = cover:analyse(t, calls, line), + ok = file:delete(File), %% Bit string comprehensions are now traversed; %% the handling of list comprehensions has been improved: @@ -1124,39 +1260,39 @@ otp_8188(Config) when is_list(Config) -> ok. bug_8188(Cf) -> - ?line [{{t,1},1},{{t,2},1},{{t,3},1}] = - analyse_expr(<<"A = 3,\n" % 1 - " case A of\n" % 1 - " 2 -> two; 3 -> three end, A + 2">>, % 1 - Cf), - - ?line [{{t,1},1}, - {{t,2},0}, - {{t,3},1}, - {{t,4},1}, - {{t,5},1}, - {{t,6},0}, - {{t,7},1}, - {{t,9},2}] = - analyse_expr(<<"case two() of\n" % 1 - " 1 -> 2;\n" % 0 - " _ -> begin 3 end\n" % 1 - " +\n" % 1 - " begin 4 end end, case two() of\n" % 1 - " 1 -> a;\n" % 0 - " 2 -> b; 3 -> c\n" % 1 - " end.\n" - "two() -> 2">>, Cf), % 2 - - ?line [{{t,1},1}, {{t,2},1}, {{t,3},1}, - {{t,4},1}, {{t,5},1}, {{t,6},0}] = - analyse_expr(<<" self() ! 1,\n" - " receive \n" - " X=1 -> a;\n" - " X=2 -> b end, case X of \n" - " 1 -> a;\n" - " 2 -> b\n" - " end">>, Cf), + [{{t,1},1},{{t,2},1},{{t,3},1}] = + analyse_expr(<<"A = 3,\n" % 1 + " case A of\n" % 1 + " 2 -> two; 3 -> three end, A + 2">>, % 1 + Cf), + + [{{t,1},1}, + {{t,2},0}, + {{t,3},1}, + {{t,4},1}, + {{t,5},1}, + {{t,6},0}, + {{t,7},1}, + {{t,9},2}] = + analyse_expr(<<"case two() of\n" % 1 + " 1 -> 2;\n" % 0 + " _ -> begin 3 end\n" % 1 + " +\n" % 1 + " begin 4 end end, case two() of\n" % 1 + " 1 -> a;\n" % 0 + " 2 -> b; 3 -> c\n" % 1 + " end.\n" + "two() -> 2">>, Cf), % 2 + + [{{t,1},1}, {{t,2},1}, {{t,3},1}, + {{t,4},1}, {{t,5},1}, {{t,6},0}] = + analyse_expr(<<" self() ! 1,\n" + " receive \n" + " X=1 -> a;\n" + " X=2 -> b end, case X of \n" + " 1 -> a;\n" + " 2 -> b\n" + " end">>, Cf), T0 = <<"t1(X) ->\n " "case X of\n" @@ -1170,42 +1306,42 @@ bug_8188(Cf) -> " end">>, T1 = [<<"a = t1(1). ">>,T0], - ?line [{{t,1},1}, {{t,2},1}, {{t,3},1}, {{t,4},0}, - {{t,5},0}, {{t,6},1}, {{t,7},1}, {{t,8},0}, {{t,9},0}] = - analyse_expr(T1, Cf), + [{{t,1},1}, {{t,2},1}, {{t,3},1}, {{t,4},0}, + {{t,5},0}, {{t,6},1}, {{t,7},1}, {{t,8},0}, {{t,9},0}] = + analyse_expr(T1, Cf), T2 = [<<"b = t1(2). ">>,T0], - ?line [{{t,1},1}, {{t,2},1}, {{t,3},0}, {{t,4},1}, - {{t,5},0}, {{t,6},1}, {{t,7},0}, {{t,8},1}, {{t,9},0}] = - analyse_expr(T2, Cf), + [{{t,1},1}, {{t,2},1}, {{t,3},0}, {{t,4},1}, + {{t,5},0}, {{t,6},1}, {{t,7},0}, {{t,8},1}, {{t,9},0}] = + analyse_expr(T2, Cf), T3 = [<<"c = t1(3). ">>,T0], - ?line [{{t,1},1}, {{t,2},1}, {{t,3},0}, {{t,4},1}, - {{t,5},1}, {{t,6},1}, {{t,7},0}, {{t,8},1}, {{t,9},0}] = - analyse_expr(T3, Cf), + [{{t,1},1}, {{t,2},1}, {{t,3},0}, {{t,4},1}, + {{t,5},1}, {{t,6},1}, {{t,7},0}, {{t,8},1}, {{t,9},0}] = + analyse_expr(T3, Cf), T4 = [<<"d = t1(4). ">>,T0], - ?line [{{t,1},1}, {{t,2},1}, {{t,3},0}, {{t,4},0}, - {{t,5},0}, {{t,6},1}, {{t,7},0}, {{t,8},0}, {{t,9},1}] = - analyse_expr(T4, Cf), - - ?line [{{t,1},1},{{t,2},1},{{t,3},1},{{t,4},1},{{t,5},1}] = - analyse_expr( - <<"2 = x3(1). " - "x3(X) ->\n" - " case X of \n" - " 1 -> case X of\n" - " 1 -> a, Y = 2;\n" - " 2 -> b, Y = 3 end, Y; 2 -> Y = 4 end, Y">>, Cf), - - ?line [{{t,1},1},{{t,2},1},{{t,3},1},{{t,4},1}] = - analyse_expr( - <<"1 = x4(1). " - "x4(X) ->\n" - " case X of\n" - " 1 -> case X of\n" - " 1 -> Y = 1 end, case X of 1 -> Y = 1 end, Y end">>, - Cf), + [{{t,1},1}, {{t,2},1}, {{t,3},0}, {{t,4},0}, + {{t,5},0}, {{t,6},1}, {{t,7},0}, {{t,8},0}, {{t,9},1}] = + analyse_expr(T4, Cf), + + [{{t,1},1},{{t,2},1},{{t,3},1},{{t,4},1},{{t,5},1}] = + analyse_expr( + <<"2 = x3(1). " + "x3(X) ->\n" + " case X of \n" + " 1 -> case X of\n" + " 1 -> a, Y = 2;\n" + " 2 -> b, Y = 3 end, Y; 2 -> Y = 4 end, Y">>, Cf), + + [{{t,1},1},{{t,2},1},{{t,3},1},{{t,4},1}] = + analyse_expr( + <<"1 = x4(1). " + "x4(X) ->\n" + " case X of\n" + " 1 -> case X of\n" + " 1 -> Y = 1 end, case X of 1 -> Y = 1 end, Y end">>, + Cf), T10 = <<"t1(X) ->\n" "if\n" @@ -1217,19 +1353,16 @@ bug_8188(Cf) -> " 2 -> b; 3 -> c\n" " end">>, T11 = [<<"a = t1(1). ">>,T10], - ?line [{{t,1},1}, {{t,2},1}, {{t,3},1}, {{t,4},1}, - {{t,5},1}, {{t,6},1}, {{t,7},1}, {{t,8},0}] = - analyse_expr(T11, Cf), + [{{t,1},1}, {{t,2},1}, {{t,3},1}, {{t,4},1}, + {{t,5},1}, {{t,6},1}, {{t,7},1}, {{t,8},0}] = analyse_expr(T11, Cf), T12 = [<<"b = t1(2). ">>,T10], - ?line [{{t,1},1}, {{t,2},1}, {{t,3},0}, {{t,4},1}, - {{t,5},0}, {{t,6},1}, {{t,7},0}, {{t,8},1}] = - analyse_expr(T12, Cf), + [{{t,1},1}, {{t,2},1}, {{t,3},0}, {{t,4},1}, + {{t,5},0}, {{t,6},1}, {{t,7},0}, {{t,8},1}] = analyse_expr(T12, Cf), T13 = [<<"c = t1(3). ">>,T10], - ?line [{{t,1},1}, {{t,2},1}, {{t,3},0}, {{t,4},1}, - {{t,5},0}, {{t,6},1}, {{t,7},0}, {{t,8},1}] = - analyse_expr(T13, Cf), + [{{t,1},1}, {{t,2},1}, {{t,3},0}, {{t,4},1}, + {{t,5},0}, {{t,6},1}, {{t,7},0}, {{t,8},1}] = analyse_expr(T13, Cf), T20 = <<"t1(X) ->\n" "case X of\n" @@ -1242,204 +1375,185 @@ bug_8188(Cf) -> " end">>, T21 = [<<"a = t1(1). ">>,T20], - ?line [{{t,1},1}, {{t,2},1}, {{t,3},1}, {{t,4},0}, - {{t,5},0}, {{t,6},1}, {{t,7},1}, {{t,8},0}] = - analyse_expr(T21, Cf), + [{{t,1},1}, {{t,2},1}, {{t,3},1}, {{t,4},0}, + {{t,5},0}, {{t,6},1}, {{t,7},1}, {{t,8},0}] = analyse_expr(T21, Cf), T22 = [<<"b = t1(2). ">>,T20], - ?line [{{t,1},1}, {{t,2},1}, {{t,3},0}, {{t,4},1}, - {{t,5},0}, {{t,6},1}, {{t,7},0}, {{t,8},1}] = - analyse_expr(T22, Cf), + [{{t,1},1}, {{t,2},1}, {{t,3},0}, {{t,4},1}, + {{t,5},0}, {{t,6},1}, {{t,7},0}, {{t,8},1}] = analyse_expr(T22, Cf), T23 = [<<"c = t1(3). ">>,T20], - ?line [{{t,1},1}, {{t,2},1}, {{t,3},0}, {{t,4},1}, - {{t,5},0}, {{t,6},1}, {{t,7},0}, {{t,8},1}] = - analyse_expr(T23, Cf), + [{{t,1},1}, {{t,2},1}, {{t,3},0}, {{t,4},1}, + {{t,5},0}, {{t,6},1}, {{t,7},0}, {{t,8},1}] = analyse_expr(T23, Cf), T30 = << - "t1(X) ->\n" - "case X of\n" - " 1 -> a;\n" - " 2 -> b; 3 -> case X of 1 -> a; 2 -> b; 3 -> c end end, case X of\n" - " 1 -> a;\n" - " 2 -> b; 3 -> c\n" - " end\n">>, + "t1(X) ->\n" + "case X of\n" + " 1 -> a;\n" + " 2 -> b; 3 -> case X of 1 -> a; 2 -> b; 3 -> c end end, case X of\n" + " 1 -> a;\n" + " 2 -> b; 3 -> c\n" + " end\n">>, T31 = [<<"a = t1(1). ">>,T30], - ?line [{{t,1},1}, {{t,2},1}, {{t,3},1}, - {{t,4},1}, {{t,5},1}, {{t,6},0}] = - analyse_expr(T31, Cf), + [{{t,1},1}, {{t,2},1}, {{t,3},1}, + {{t,4},1}, {{t,5},1}, {{t,6},0}] = analyse_expr(T31, Cf), T32 = [<<"b = t1(2). ">>,T30], - ?line [{{t,1},1}, {{t,2},1}, {{t,3},0}, - {{t,4},1}, {{t,5},0}, {{t,6},1}] = - analyse_expr(T32, Cf), + [{{t,1},1}, {{t,2},1}, {{t,3},0}, + {{t,4},1}, {{t,5},0}, {{t,6},1}] = analyse_expr(T32, Cf), T33 = [<<"c = t1(3). ">>,T30], - ?line [{{t,1},1}, {{t,2},1}, {{t,3},0}, - {{t,4},1}, {{t,5},0}, {{t,6},1}] = - analyse_expr(T33, Cf), + [{{t,1},1}, {{t,2},1}, {{t,3},0}, + {{t,4},1}, {{t,5},0}, {{t,6},1}] = analyse_expr(T33, Cf), %% 'try' now traverses the body as a body... - ?line [{{t,1},1},{{t,2},1},{{t,3},1},{{t,4},0},{{t,6},1}] = - analyse_expr(<<"try \n" - " B = 2, \n" - " C = erlang:error(foo), \n" - " {B,C} \n" - "catch _:_ -> \n" - " foo \n" - "end">>, Cf), + [{{t,1},1},{{t,2},1},{{t,3},1},{{t,4},0},{{t,6},1}] = + analyse_expr(<<"try \n" + " B = 2, \n" + " C = erlang:error(foo), \n" + " {B,C} \n" + "catch _:_ -> \n" + " foo \n" + "end">>, Cf), %% receive after: - ?line [{{t,1},1},{{t,2},0},{{t,3},1}] = - analyse_expr(<<"receive \n" - " X=1 -> a; \n" - " X=2 -> b after begin 10 end -> X=3 end">>, Cf), - ?line [{{t,1},1},{{t,2},0},{{t,3},1}] = - analyse_expr(<<"receive \n" - " X=1 -> a; \n" - " X=2 -> b after 10 -> begin X=3 end end">>, Cf), + [{{t,1},1},{{t,2},0},{{t,3},1}] = + analyse_expr(<<"receive \n" + " X=1 -> a; \n" + " X=2 -> b after begin 10 end -> X=3 end">>, Cf), + [{{t,1},1},{{t,2},0},{{t,3},1}] = + analyse_expr(<<"receive \n" + " X=1 -> a; \n" + " X=2 -> b after 10 -> begin X=3 end end">>, Cf), ok. comprehension_8188(Cf) -> - ?line [{{t,1},1}] = - analyse_expr(<<"[begin X end || X <- [1,2,3], X > 1]">>, Cf), - ?line [{{t,1},1},{{t,2},1}] = - analyse_expr(<<"[begin X end || \n" - " X <- [1,2,3], X > 1]">>, Cf), - ?line [{{t,1},1},{{t,2},1},{{t,3},3}] = - analyse_expr(<<"[begin X end || \n " - " X <- [1,2,3], \n " - " X > 1]">>, Cf), - ?line [{{t,1},1},{{t,3},1},{{t,4},3}] = - analyse_expr(<<"[begin X end || \n " - " X <- \n " - " [1,2,3], \n " - " X > 1]">>, Cf), - ?line [{{t,1},1},{{t,2},2}] = - analyse_expr(<<"[ \n " - " X || X <- [1,2,3], X > 1]">>, Cf), - ?line [{{t,1},1},{{t,2},2},{{t,3},3}] = - analyse_expr(<<"[ \n" - " X || X <- [1,2,3], \n" - " X > 1]">>, Cf), - ?line [{{t,1},1},{{t,2},1},{{t,3},2}] = - analyse_expr(<<"[ \n " - " X || X <- [1,2,3], X > 1, \n" - " X > 2]">>, Cf), - - ?line [{{t,1},1}, - {{t,3},2}, - {{t,5},1}, - {{t,7},1}, - {{t,8},0}, - {{t,12},3}, - {{t,15},2}, - {{t,17},2}, - {{t,18},1}] = - analyse_expr(<<"[ \n" % 1 - " begin\n" - " X * 2\n" % 2 - " end ||\n" - " X <- [1,\n" % 1 - " case two() of\n" - " 2 -> 2;\n" % 1 - " _ -> two\n" % 0 - " end,\n" - " 3],\n" - " begin\n" - " math:sqrt(X) > 1.0\n" % 3 - " end,\n" - " begin\n" - " true\n" % 2 - " end,\n" - " true]. \n" % 2 - " two() -> 2">>, Cf), % 1 - - ?line [{{t,1},1}, - {{t,2},2}, - {{t,3},1}, - {{t,5},1}, - {{t,6},0}, - {{t,9},3}, - {{t,10},2}, - {{t,11},2}, - {{t,12},1}] = - analyse_expr(<<"[ \n" - " X * 2 || \n" % 2 - " X <- [1,\n" % 1 - " case two() of\n" - " 2 -> 2;\n" % 1 - " _ -> two\n" % 0 - " end,\n" - " 3],\n" - " math:sqrt(X) > 1.0,\n" % 3 - " true,\n" % 2 - " true]. \n" % 2 - " two() -> 2">>, Cf), % 1 - - ?line [{{t,1},1}, - {{t,2},2}, - {{t,3},1}, - {{t,4},1}, - {{t,5},0}, - {{t,8},1}, - {{t,9},0}, - {{t,12},3}, - {{t,13},2}, - {{t,14},2}] = - analyse_expr(<<"<< \n" % 1 - " << (X*2) >> || \n" % 2 - " <<X>> <= << (case two() of\n" - " 2 -> 1;\n" % 1 - " _ -> 2\n" % 0 - " end)/integer,\n" - " (case two() of \n" - " 2 -> 2;\n" % 1 - " _ -> two\n" % 0 - " end)/integer,\n" - " 3 >>, \n" - " math:sqrt(X) > 1.0,\n" % 3 - " true >>.\n" % 2 - "two() -> 2">>, Cf), - - ?line [{{t,1},1}, - {{t,2},4}, - {{t,4},1}, - {{t,6},1}, - {{t,7},0}, - {{t,10},3}, - {{t,11},2}, - {{t,12},4}, - {{t,13},1}] = - analyse_expr(<<"<< \n" % 1 - " << (2)\n" % 4 - " :(8) >> || \n" - " <<X>> <= << 1,\n" % 1 - " (case two() of \n" - " 2 -> 2;\n" % 1 - " _ -> two\n" % 0 - " end)/integer,\n" - " 3 >>, \n" - " math:sqrt(X) > 1.0,\n" % 3 - " <<_>> <= << 1, 2 >>,\n" % 2 - " true >>.\n" % 4 - "two() -> 2">>, Cf), % 1 - + [{{t,1},1}] = analyse_expr(<<"[begin X end || X <- [1,2,3], X > 1]">>, Cf), + [{{t,1},1},{{t,2},1}] = analyse_expr(<<"[begin X end || \n" + " X <- [1,2,3], X > 1]">>, Cf), + [{{t,1},1},{{t,2},1},{{t,3},3}] = analyse_expr(<<"[begin X end || \n " + " X <- [1,2,3], \n " + " X > 1]">>, Cf), + [{{t,1},1},{{t,3},1},{{t,4},3}] = analyse_expr(<<"[begin X end || \n " + " X <- \n " + " [1,2,3], \n " + " X > 1]">>, Cf), + [{{t,1},1},{{t,2},2}] = analyse_expr(<<"[ \n " + " X || X <- [1,2,3], X > 1]">>, Cf), + [{{t,1},1},{{t,2},2},{{t,3},3}] = analyse_expr(<<"[ \n" + " X || X <- [1,2,3], \n" + " X > 1]">>, Cf), + [{{t,1},1},{{t,2},1},{{t,3},2}] = analyse_expr(<<"[ \n " + " X || X <- [1,2,3], X > 1, \n" + " X > 2]">>, Cf), + + [{{t,1},1}, + {{t,3},2}, + {{t,5},1}, + {{t,7},1}, + {{t,8},0}, + {{t,12},3}, + {{t,15},2}, + {{t,17},2}, + {{t,18},1}] = analyse_expr(<<"[ \n" % 1 + " begin\n" + " X * 2\n" % 2 + " end ||\n" + " X <- [1,\n" % 1 + " case two() of\n" + " 2 -> 2;\n" % 1 + " _ -> two\n" % 0 + " end,\n" + " 3],\n" + " begin\n" + " math:sqrt(X) > 1.0\n" % 3 + " end,\n" + " begin\n" + " true\n" % 2 + " end,\n" + " true]. \n" % 2 + " two() -> 2">>, Cf), % 1 + + [{{t,1},1}, + {{t,2},2}, + {{t,3},1}, + {{t,5},1}, + {{t,6},0}, + {{t,9},3}, + {{t,10},2}, + {{t,11},2}, + {{t,12},1}] = analyse_expr(<<"[ \n" + " X * 2 || \n" % 2 + " X <- [1,\n" % 1 + " case two() of\n" + " 2 -> 2;\n" % 1 + " _ -> two\n" % 0 + " end,\n" + " 3],\n" + " math:sqrt(X) > 1.0,\n" % 3 + " true,\n" % 2 + " true]. \n" % 2 + " two() -> 2">>, Cf), % 1 + + [{{t,1},1}, + {{t,2},2}, + {{t,3},1}, + {{t,4},1}, + {{t,5},0}, + {{t,8},1}, + {{t,9},0}, + {{t,12},3}, + {{t,13},2}, + {{t,14},2}] = analyse_expr(<<"<< \n" % 1 + " << (X*2) >> || \n" % 2 + " <<X>> <= << (case two() of\n" + " 2 -> 1;\n" % 1 + " _ -> 2\n" % 0 + " end)/integer,\n" + " (case two() of \n" + " 2 -> 2;\n" % 1 + " _ -> two\n" % 0 + " end)/integer,\n" + " 3 >>, \n" + " math:sqrt(X) > 1.0,\n" % 3 + " true >>.\n" % 2 + "two() -> 2">>, Cf), + [{{t,1},1}, + {{t,2},4}, + {{t,4},1}, + {{t,6},1}, + {{t,7},0}, + {{t,10},3}, + {{t,11},2}, + {{t,12},4}, + {{t,13},1}] = analyse_expr(<<"<< \n" % 1 + " << (2)\n" % 4 + " :(8) >> || \n" + " <<X>> <= << 1,\n" % 1 + " (case two() of \n" + " 2 -> 2;\n" % 1 + " _ -> two\n" % 0 + " end)/integer,\n" + " 3 >>, \n" + " math:sqrt(X) > 1.0,\n" % 3 + " <<_>> <= << 1, 2 >>,\n" % 2 + " true >>.\n" % 4 + "two() -> 2">>, Cf), % 1 ok. eep37(Config) when is_list(Config) -> [{{t,1},1},{{t,2},1},{{t,4},6},{{t,6},1},{{t,8},1}] = - analyse_expr(<<"begin\n" % 1 - " F =\n" % 1 - " fun Fact(N) when N > 0 ->\n" - " N * Fact(N - 1);\n" % 6 - " Fact(0) ->\n" - " 1\n" % 1 - " end,\n" - " F(6)\n" % 1 - "end\n">>, - Config), + analyse_expr(<<"begin\n" % 1 + " F =\n" % 1 + " fun Fact(N) when N > 0 ->\n" + " N * Fact(N - 1);\n" % 6 + " Fact(0) ->\n" + " 1\n" % 1 + " end,\n" + " F(6)\n" % 1 + "end\n">>, + Config), ok. otp_10979_hanging_node(_Config) -> @@ -1452,42 +1566,40 @@ otp_10979_hanging_node(_Config) -> P2 = processes(), case P2--P1 of - [] -> - ok; - New -> - [io:format("New: ~p, ~p~n",[P,process_info(P)]) || P<-New], - ct:fail(hanging_process) + [] -> + ok; + New -> + [io:format("New: ~p, ~p~n",[P,process_info(P)]) || P<-New], + ct:fail(hanging_process) end, ok. -compile_beam_opts(doc) -> - ["Take compiler options from beam in cover:compile_beam"]; -compile_beam_opts(suite) -> []; +%% Take compiler options from beam in cover:compile_beam compile_beam_opts(Config) when is_list(Config) -> {ok, Cwd} = file:get_cwd(), - ok = file:set_cwd(?config(priv_dir, Config)), - IncDir = filename:join(?config(data_dir, Config), - "included_functions"), - File = filename:join([?config(data_dir, Config), "otp_11439", "t.erl"]), + ok = file:set_cwd(proplists:get_value(priv_dir, Config)), + IncDir = filename:join(proplists:get_value(data_dir, Config), + "included_functions"), + File = filename:join([proplists:get_value(data_dir, Config), "otp_11439", "t.erl"]), %% use all compiler options allowed by cover:filter_options %% i and d don't make sense when compiling from beam though {ok, t} = - compile:file(File, [{i, IncDir}, - {d, 'BOOL'}, - {d, 'MACRO', macro_defined}, - export_all, - debug_info, - return_errors]), + compile:file(File, [{i, IncDir}, + {d, 'BOOL'}, + {d, 'MACRO', macro_defined}, + export_all, + debug_info, + return_errors]), code:purge(t), code:delete(t), Exports = - [{func1,0}, - {macro, 0}, - {exported,0}, - {nonexported,0}, - {module_info,0}, - {module_info,1}], + [{func1,0}, + {macro, 0}, + {exported,0}, + {nonexported,0}, + {module_info,0}, + {module_info,1}], Exports = t:module_info(exports), {ok, t} = cover:compile_beam("t"), Exports = t:module_info(exports), @@ -1495,6 +1607,118 @@ compile_beam_opts(Config) when is_list(Config) -> ok = file:set_cwd(Cwd), ok. +%% Don't crash if beam is not available +analyse_no_beam(Config) when is_list(Config) -> + {ok, Cwd} = file:get_cwd(), + ok = file:set_cwd(proplists:get_value(data_dir, Config)), + + code:purge(t), + code:delete(t), + + {ok,_} = file:copy("compile_beam/t.erl", "t.erl"), + {ok,t} = compile:file(t, [debug_info]), + {module,t} = code:load_file(t), + {ok,t} = cover:compile_beam(t), + t:f(), + ok = cover:export("t.coverdata"), + + code:purge(t), + code:delete(t), + + %% this is just so that cover realises (without stopping) + %% that this module is not cover compiled any more + {error, {not_cover_compiled,t}} = cover:analyse(t), + + %% source and beam not available any more + ok = file:delete("t.erl"), + ok = file:delete("t.beam"), + + ok = cover:import("t.coverdata"), + + {error,{no_source_code_found,t}} = cover:analyse_to_file(t), + {result,[],[{no_source_code_found,t}]} = cover:analyse_to_file([t]), + + ok = file:delete("t.coverdata"), + ok = file:set_cwd(Cwd), + ok. + +%% When including eunit.hrl, a parse transform adds the function +%% test/0 to line 0 in your module. A bug in OTP-18.0 caused +%% cover:analyse_to_file/1 to fail to insert cover data in the output +%% file in this situation. The test below tests that this bug is +%% corrected. +line_0(Config) -> + ok = file:set_cwd(filename:join(proplists:get_value(data_dir, Config), + "include_eunit_hrl")), + {ok, cover_inc_eunit} = compile:file(cover_inc_eunit,[debug_info]), + {ok, cover_inc_eunit} = cover:compile_beam(cover_inc_eunit), + {ok, CovOut} = cover:analyse_to_file(cover_inc_eunit), + + {ok,Bin} = file:read_file(CovOut), + Match = <<"0..| ok.\n">>, % "0.." is missing when bug is there + S = byte_size(Bin)-byte_size(Match), + <<_:S/binary,Match/binary>> = Bin, + ok. + + +%% OTP-13200: Return error instead of crashing when trying to compile +%% a beam which has no 'file' attribute. +compile_beam_no_file(Config) -> + PrivDir = proplists:get_value(priv_dir,Config), + Dir = filename:join(PrivDir,"compile_beam_no_file"), + ok = filelib:ensure_dir(filename:join(Dir,"*")), + code:add_patha(Dir), + Str = lists:concat( + ["-module(nofile).\n" + "-compile(export_all).\n" + "foo() -> ok.\n"]), + TT = do_scan(Str), + Forms = [ begin {ok,Y} = erl_parse:parse_form(X),Y end || X <- TT ], + {ok,_,Bin} = compile:forms(Forms,[debug_info]), + BeamFile = filename:join(Dir,"nofile.beam"), + ok = file:write_file(BeamFile,Bin), + {error,{no_file_attribute,BeamFile}} = cover:compile_beam(nofile), + [{error,{no_file_attribute,BeamFile}}] = cover:compile_beam_directory(Dir), + ok. + +do_scan([]) -> + []; +do_scan(Str) -> + {done,{ok,T,_},C} = erl_scan:tokens([],Str,0), + [ T | do_scan(C) ]. + +%% PR 856. Fix a bc bug. +otp_13277(Config) -> + Test = <<"-module(t). + -export([t/0]). + + pad(A, L) -> + P = << <<\"#\">> || _ <- lists:seq(1, L) >>, + <<A/binary, P/binary>>. + + t() -> + pad(<<\"hi\">>, 2). + ">>, + File = cc_mod(t, Test, Config), + <<"hi##">> = t:t(), + ok = file:delete(File), + ok. + +%% Test general expressions in a binary comprehension. +otp_13289(Config) -> + Test = <<"-module(t). + -export([t/0]). + + t() -> + << (id(<<I>>)) || I <- [1,2,3] >>. + + id(I) -> I. + ">>, + File = cc_mod(t, Test, Config), + <<1,2,3>> = t:t(), + ok = file:delete(File), + ok. + %%--Auxiliary------------------------------------------------------------ analyse_expr(Expr, Config) -> @@ -1509,7 +1733,7 @@ analyse_expr(Expr, Config) -> cc_mod(M, Binary, Config) -> {ok, Dir} = file:get_cwd(), - PrivDir = ?config(priv_dir, Config), + PrivDir = proplists:get_value(priv_dir, Config), ok = file:set_cwd(PrivDir), File = atom_to_list(M) ++ ".erl", try @@ -1521,7 +1745,7 @@ cc_mod(M, Binary, Config) -> c_mod(M, Binary, Config) -> {ok, Dir} = file:get_cwd(), - PrivDir = ?config(priv_dir, Config), + PrivDir = proplists:get_value(priv_dir, Config), ok = file:set_cwd(PrivDir), File = atom_to_list(M) ++ ".erl", try @@ -1544,12 +1768,12 @@ lsfiles(Dir) -> files(Files, Ext) -> lists:filter(fun(File) -> - case filename:extension(File) of - Ext -> true; - _ -> false - end - end, - Files). + case filename:extension(File) of + Ext -> true; + _ -> false + end + end, + Files). remove([File|Files]) -> ok = file:delete(File), @@ -1566,28 +1790,30 @@ decompile([]) -> is_unloaded(What) -> if - is_list(What) -> true; - What==non_existing -> true; - true -> false + is_list(What) -> true; + What==non_existing -> true; + true -> false end. check_f_calls(F1,F2) -> - {ok,[{{f,f1,0},F1},{{f,f2,0},F2}|_]} = cover:analyse(f,calls,function). + {ok,A} = cover:analyse(f,calls,function), + {_,F1} = lists:keyfind({f,f1,0},1,A), + {_,F2} = lists:keyfind({f,f2,0},1,A). cover_which_nodes(Expected) -> case cover:which_nodes() of - Expected -> - ok; - Other -> - {Time,ok} = timer:tc(fun Retry() -> - case cover:which_nodes() of - Expected -> ok; - _ -> - ?t:sleep(100), - Retry() - end - end), - io:format("~p ms before cover:which_nodes() returned ~p", - [Time,Expected]), - Expected = Other + Expected -> + ok; + Other -> + {Time,ok} = timer:tc(fun Retry() -> + case cover:which_nodes() of + Expected -> ok; + _ -> + timer:sleep(100), + Retry() + end + end), + io:format("~p ms before cover:which_nodes() returned ~p", + [Time,Expected]), + Expected = Other end. diff --git a/lib/tools/test/cover_SUITE_data/cc.erl b/lib/tools/test/cover_SUITE_data/cc.erl index 587bdbe493..7eb165ef8a 100644 --- a/lib/tools/test/cover_SUITE_data/cc.erl +++ b/lib/tools/test/cover_SUITE_data/cc.erl @@ -1,88 +1,17 @@ -module(cc). --export([epp/1, epp/2, dbg/1, dbg/2, cvr/1, cvr/2]). --export([p/2, pp/2]). +-compile(export_all). -%% epp(Module) - Creates Module.epp which contains all forms of Module -%% as obtained by using epp. -%% -%% dbg(Module) - Creates Module.dbg which contains all forms of Module -%% as obtained by using beam_lib:chunks/2. -%% -%% cvr(Module) - Creates Module.cvr which contains all forms of Module -%% as obtained by using cover:transform/3. -%% +%% This is a dummy module used only for cover compiling. The content +%% of this module has no meaning for the test. -epp(Module) -> - epp(Module, p). -epp(Module, P) -> - File = atom_to_list(Module)++".erl", - {ok,Cwd} = file:get_cwd(), - {ok, Fd1} = epp:open(File, [Cwd], []), - {ok, Fd2} = file:open(atom_to_list(Module)++".epp", write), +foo() -> + T = erlang:time(), + spawn(fun() -> bar(T) end). - epp(Fd1, Fd2, P), - - epp:close(Fd1), - file:close(Fd2), - ok. - -epp(Fd1, Fd2, P) -> - case epp:parse_erl_form(Fd1) of - {ok, {attribute,Line,Attr,Data}} -> - epp(Fd1, Fd2, P); - {ok, Form} when P==p -> - io:format(Fd2, "~p.~n", [Form]), - epp(Fd1, Fd2, P); - {ok, Form} when P==pp -> - io:format(Fd2, "~p.~n", [erl_pp:form(Form)]), - epp(Fd1, Fd2, P); - {eof, Line} -> - ok - end. - -cvr(Module) -> - cvr(Module, p). -cvr(Module, P) -> - case beam_lib:chunks(Module, [abstract_code]) of - {ok, {Module, [{abstract_code, no_abstract_code}]}} -> - {error, {no_debug_info,Module}}; - {ok, {Module, [{abstract_code, {Vsn, Forms}}]}} -> - Vars = {vars,Module,Vsn, [], - undefined, undefined, undefined, undefined, undefined, - undefined, - false}, - {ok, TForms, _Vars2} = cover:transform(Forms, [], Vars), - File = atom_to_list(Module)++".cvr", - apply(?MODULE, P, [File, TForms]); - Error -> - Error +bar(T) -> + receive + X -> + T1 = erlang:time(), + io:format("received ~p at ~p. Last time: ~p~n",[X,T1,T]), + bar(T1) end. - -dbg(Module) -> - dbg(Module, p). -dbg(Module, P) -> - case beam_lib:chunks(Module, [abstract_code]) of - {ok, {Module, [{abstract_code, no_abstract_code}]}} -> - {error, {no_debug_info,Module}}; - {ok, {Module, [{abstract_code, {Vsn, Forms}}]}} -> - File = atom_to_list(Module)++".dbg", - apply(?MODULE, P, [File, Forms]); - Error -> - Error - end. - -p(File, Forms) -> - {ok, Fd} = file:open(File, write), - lists:foreach(fun(Form) -> - io:format(Fd, "~p.~n", [Form]) - end, - Forms), - file:close(Fd). - -pp(File, Forms) -> - {ok, Fd} = file:open(File, write), - lists:foreach(fun(Form) -> - io:format(Fd, "~s", [erl_pp:form(Form)]) - end, - Forms), - file:close(Fd). diff --git a/lib/tools/test/cover_SUITE_data/compile_beam/t.erl b/lib/tools/test/cover_SUITE_data/compile_beam/t.erl new file mode 100644 index 0000000000..96dc2f4209 --- /dev/null +++ b/lib/tools/test/cover_SUITE_data/compile_beam/t.erl @@ -0,0 +1,6 @@ +-module(t). + +-export([f/0]). + +f() -> + ok. diff --git a/lib/tools/test/cover_SUITE_data/d.erl b/lib/tools/test/cover_SUITE_data/d.erl index 696e27e49b..b1d8ebd62e 100644 --- a/lib/tools/test/cover_SUITE_data/d.erl +++ b/lib/tools/test/cover_SUITE_data/d.erl @@ -6,7 +6,7 @@ size/0]). -export([init/0]). % spawn --record(person, {name, age, location, moved=false}). +-record(person, {name, age :: integer(), location, moved=false :: boolean()}). %%%---------------------------------------------------------------------- %%% User interface functions diff --git a/lib/tools/test/cover_SUITE_data/include_eunit_hrl/cover_inc_eunit.erl b/lib/tools/test/cover_SUITE_data/include_eunit_hrl/cover_inc_eunit.erl new file mode 100644 index 0000000000..c1fe7939d2 --- /dev/null +++ b/lib/tools/test/cover_SUITE_data/include_eunit_hrl/cover_inc_eunit.erl @@ -0,0 +1,6 @@ +-module(cover_inc_eunit). +-compile(export_all). +-include_lib("eunit/include/eunit.hrl"). + +func() -> + ok. diff --git a/lib/tools/test/cprof_SUITE.erl b/lib/tools/test/cprof_SUITE.erl index fa4068dade..9cbc27fb17 100644 --- a/lib/tools/test/cprof_SUITE.erl +++ b/lib/tools/test/cprof_SUITE.erl @@ -1,18 +1,19 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2013. All Rights Reserved. +%% Copyright Ericsson AB 2002-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% 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 %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% @@ -41,9 +42,9 @@ -define(config(A,B),config(A,B)). -export([config/2]). -else. --include_lib("test_server/include/test_server.hrl"). +-include_lib("common_test/include/ct.hrl"). -endif. - + -ifdef(debug). -ifdef(STANDALONE). -define(line, erlang:display({?MODULE,?LINE}), ). @@ -55,7 +56,7 @@ -endif. -define(dbgformat(A,B),noop). -endif. - + -ifdef(STANDALONE). config(priv_dir, _) -> "."; @@ -63,69 +64,43 @@ config(data_dir, _) -> "cprof_SUITE_data". -else. %% When run in test server. --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2, - init_per_testcase/2, end_per_testcase/2, - not_run/1]). +-export([all/0, suite/0, + init_per_testcase/2, end_per_testcase/2, + not_run/1]). -export([basic/1, on_load/1, modules/1]). - + init_per_testcase(_Case, Config) -> - ?line Dog=test_server:timetrap(test_server:seconds(30)), - [{watchdog, Dog}|Config]. + Config. -end_per_testcase(_Case, Config) -> +end_per_testcase(_Case, _Config) -> erlang:trace_pattern({'_','_','_'}, false, [local,meta,call_count]), erlang:trace_pattern(on_load, false, [local,meta,call_count]), erlang:trace(all, false, [all]), - Dog=?config(watchdog, Config), - test_server:timetrap_cancel(Dog), ok. -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap,{seconds,30}}]. all() -> case test_server:is_native(cprof_SUITE) of - true -> [not_run]; - false -> [basic, on_load, modules] + true -> [not_run]; + false -> [basic, on_load, modules] end. -groups() -> - []. - -init_per_suite(Config) -> - Config. - -end_per_suite(_Config) -> - ok. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - not_run(Config) when is_list(Config) -> {skipped,"Native code"}. -basic(suite) -> - []; -basic(doc) -> - ["Tests basic profiling"]; +%% Tests basic profiling basic(Config) when is_list(Config) -> basic_test(). -on_load(suite) -> - []; -on_load(doc) -> - ["Tests profiling of unloaded module"]; +%% Tests profiling of unloaded module on_load(Config) when is_list(Config) -> on_load_test(Config). -modules(suite) -> - []; -modules(doc) -> - ["Tests profiling of several modules"]; +%% Tests profiling of several modules modules(Config) when is_list(Config) -> modules_test(Config). @@ -136,164 +111,163 @@ modules(Config) when is_list(Config) -> %%% basic_test() -> - ?line M = 1000, + M = 1000, %% - ?line M2 = M*2, - ?line M3 = M*3, - ?line M2__1 = M2 + 1, - ?line M3__1 = M3 + 1, - ?line N = cprof:stop(), + M2 = M*2, + M3 = M*3, + M2__1 = M2 + 1, + M3__1 = M3 + 1, + N = cprof:stop(), %% - ?line 2 = cprof:start(?MODULE, seq_r), - ?line 1 = cprof:start(?MODULE, seq, 3), - ?line L = seq(1, M, fun succ/1), - ?line Lr = seq_r(1, M, fun succ/1), - ?line L = lists:reverse(Lr), + 2 = cprof:start(?MODULE, seq_r), + 1 = cprof:start(?MODULE, seq, 3), + L = seq(1, M, fun succ/1), + Lr = seq_r(1, M, fun succ/1), + L = lists:reverse(Lr), %% - ?line io:format("~p~n~p~n~p~n", - [erlang:trace_info({?MODULE,sec_r,3}, all), - erlang:trace_info({?MODULE,sec_r,4}, all), - erlang:trace_info({?MODULE,sec,3}, all)]), + io:format("~p~n~p~n~p~n", + [erlang:trace_info({?MODULE,sec_r,3}, all), + erlang:trace_info({?MODULE,sec_r,4}, all), + erlang:trace_info({?MODULE,sec,3}, all)]), %% - ?line ModAna1 = {?MODULE,M2__1,[{{?MODULE,seq_r,4},M}, - {{?MODULE,seq,3},M}, - {{?MODULE,seq_r,3},1}]}, - ?line ModAna1 = cprof:analyse(?MODULE,0), - ?line {M2__1, [ModAna1]} = cprof:analyse(), - ?line ModAna1 = cprof:analyse(?MODULE, 1), - ?line {M2__1, [ModAna1]} = cprof:analyse(1), + ModAna1 = {?MODULE,M2__1,[{{?MODULE,seq_r,4},M}, + {{?MODULE,seq,3},M}, + {{?MODULE,seq_r,3},1}]}, + ModAna1 = cprof:analyse(?MODULE,0), + {M2__1, [ModAna1]} = cprof:analyse(), + ModAna1 = cprof:analyse(?MODULE, 1), + {M2__1, [ModAna1]} = cprof:analyse(1), %% - ?line ModAna2 = {?MODULE,M2__1,[{{?MODULE,seq_r,4},M}, - {{?MODULE,seq,3},M}]}, - ?line ModAna2 = cprof:analyse(?MODULE, 2), - ?line {M2__1, [ModAna2]} = cprof:analyse(2), + ModAna2 = {?MODULE,M2__1,[{{?MODULE,seq_r,4},M}, + {{?MODULE,seq,3},M}]}, + ModAna2 = cprof:analyse(?MODULE, 2), + {M2__1, [ModAna2]} = cprof:analyse(2), %% 2 = cprof:pause(?MODULE, seq_r), - ?line L = seq(1, M, fun succ/1), - ?line Lr = seq_r(1, M, fun succ/1), + L = seq(1, M, fun succ/1), + Lr = seq_r(1, M, fun succ/1), %% - ?line ModAna3 = {?MODULE,M3__1,[{{?MODULE,seq,3},M2}, - {{?MODULE,seq_r,4},M}, - {{?MODULE,seq_r,3},1}]}, - ?line ModAna3 = cprof:analyse(?MODULE), + ModAna3 = {?MODULE,M3__1,[{{?MODULE,seq,3},M2}, + {{?MODULE,seq_r,4},M}, + {{?MODULE,seq_r,3},1}]}, + ModAna3 = cprof:analyse(?MODULE), %% - ?line N = cprof:pause(), - ?line L = seq(1, M, fun succ/1), - ?line Lr = seq_r(1, M, fun succ/1), + N = cprof:pause(), + L = seq(1, M, fun succ/1), + Lr = seq_r(1, M, fun succ/1), %% - ?line {M3__1, [ModAna3]} = cprof:analyse(), + {M3__1, [ModAna3]} = cprof:analyse(), %% - ?line N = cprof:restart(), - ?line L = seq(1, M, fun succ/1), - ?line Lr = seq_r(1, M, fun succ/1), + N = cprof:restart(), + L = seq(1, M, fun succ/1), + Lr = seq_r(1, M, fun succ/1), %% - ?line ModAna1 = cprof:analyse(?MODULE), + ModAna1 = cprof:analyse(?MODULE), %% - ?line N = cprof:stop(), - ?line {?MODULE,0,[]} = cprof:analyse(?MODULE), - ?line {0,[]} = cprof:analyse(), + N = cprof:stop(), + {?MODULE,0,[]} = cprof:analyse(?MODULE), + {0,[]} = cprof:analyse(), ok. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% on_load_test(Config) -> - ?line Priv = ?config(priv_dir, Config), - ?line Data = ?config(data_dir, Config), - ?line File = filename:join(Data, "cprof_SUITE_test"), - ?line Module = cprof_SUITE_test, - ?line M = 1000, + Priv = proplists:get_value(priv_dir, Config), + Data = proplists:get_value(data_dir, Config), + File = filename:join(Data, "cprof_SUITE_test"), + Module = cprof_SUITE_test, + M = 1000, %% - ?line M2 = M*2, - ?line M2__1 = M2 + 1, - ?line N1 = cprof:start(), + M2 = M*2, + M2__1 = M2 + 1, + N1 = cprof:start(), - ?line {ok,Module} = c:c(File, [{outdir,Priv}]), + {ok,Module} = c:c(File, [{outdir,Priv}]), %% If this system is hipe-enabled, the loader may have called module_info/1 %% when Module was loaded above. Reset the call count to avoid seeing %% the call in the analysis below. - ?line 1 = cprof:restart(Module, module_info, 1), - - ?line L = Module:seq(1, M, fun succ/1), - ?line Lr = Module:seq_r(1, M, fun succ/1), - ?line Lr = lists:reverse(L), - ?line N2 = cprof:pause(), - ?line N3 = cprof:pause(Module), - ?line {Module,M2__1,[{{Module,seq_r,4},M}, - {{Module,seq,3},M}, - {{Module,seq_r,3},1}]} = cprof:analyse(Module), - ?line io:format("~p ~p ~p~n", [N1, N2, N3]), - ?line code:purge(Module), - ?line code:delete(Module), - ?line N4 = N2 - N3, + 1 = cprof:restart(Module, module_info, 1), + + L = Module:seq(1, M, fun succ/1), + Lr = Module:seq_r(1, M, fun succ/1), + Lr = lists:reverse(L), + N2 = cprof:pause(), + N3 = cprof:pause(Module), + {Module,M2__1,[{{Module,seq_r,4},M}, + {{Module,seq,3},M}, + {{Module,seq_r,3},1}]} = cprof:analyse(Module), + io:format("~p ~p ~p~n", [N1, N2, N3]), + code:purge(Module), + code:delete(Module), + N4 = N2 - N3, %% - ?line N4 = cprof:restart(), - ?line {ok,Module} = c:c(File, [{outdir,Priv}]), - ?line L = Module:seq(1, M, fun succ/1), - ?line Lr = Module:seq_r(1, M, fun succ/1), - ?line L = seq(1, M, fun succ/1), - ?line Lr = seq_r(1, M, fun succ/1), - ?line N2 = cprof:pause(), - ?line {Module,0,[]} = cprof:analyse(Module), - ?line M_1 = M - 1, - ?line M4__4 = M*4 - 4, - ?line M10_7 = M*10 - 7, - ?line {?MODULE,M10_7,[{{?MODULE,succ,1},M4__4}, - {{?MODULE,seq_r,4},M}, - {{?MODULE,seq,3},M}, - {{?MODULE,'-on_load_test/1-fun-5-',1},M_1}, - {{?MODULE,'-on_load_test/1-fun-4-',1},M_1}, - {{?MODULE,'-on_load_test/1-fun-3-',1},M_1}, - {{?MODULE,'-on_load_test/1-fun-2-',1},M_1}, - {{?MODULE,seq_r,3},1}]} - = cprof:analyse(?MODULE), - ?line N2 = cprof:stop(), + N4 = cprof:restart(), + {ok,Module} = c:c(File, [{outdir,Priv}]), + L = Module:seq(1, M, fun succ/1), + Lr = Module:seq_r(1, M, fun succ/1), + L = seq(1, M, fun succ/1), + Lr = seq_r(1, M, fun succ/1), + N2 = cprof:pause(), + {Module,0,[]} = cprof:analyse(Module), + M_1 = M - 1, + M4__4 = M*4 - 4, + M10_7 = M*10 - 7, + {?MODULE,M10_7,[{{?MODULE,succ,1},M4__4}, + {{?MODULE,seq_r,4},M}, + {{?MODULE,seq,3},M}, + {{?MODULE,'-on_load_test/1-fun-5-',1},M_1}, + {{?MODULE,'-on_load_test/1-fun-4-',1},M_1}, + {{?MODULE,'-on_load_test/1-fun-3-',1},M_1}, + {{?MODULE,'-on_load_test/1-fun-2-',1},M_1}, + {{?MODULE,seq_r,3},1}]} + = cprof:analyse(?MODULE), + N2 = cprof:stop(), ok. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% modules_test(Config) -> - ?line Priv = ?config(priv_dir, Config), - ?line Data = ?config(data_dir, Config), - ?line File = filename:join(Data, "cprof_SUITE_test"), - ?line Module = cprof_SUITE_test, - ?line {ok,Module} = c:c(File, [{outdir,Priv}]), - ?line M = 10, + Priv = proplists:get_value(priv_dir, Config), + Data = proplists:get_value(data_dir, Config), + File = filename:join(Data, "cprof_SUITE_test"), + Module = cprof_SUITE_test, + {ok,Module} = c:c(File, [{outdir,Priv}]), + M = 10, %% - ?line M2 = M*2, - ?line M2__1 = M2 + 1, - ?line erlang:yield(), - ?line N = cprof:start(), - ?line L = Module:seq(1, M, fun succ/1), - ?line Lr = Module:seq_r(1, M, fun succ/1), - ?line L = seq(1, M, fun succ/1), - ?line Lr = seq_r(1, M, fun succ/1), - ?line N = cprof:pause(), - ?line Lr = lists:reverse(L), - ?line M_1 = M - 1, - ?line M4_4 = M*4 - 4, - ?line M10_7 = M*10 - 7, - ?line M2__1 = M*2 + 1, - ?line {Tot,ModList} = cprof:analyse(), - ?line {value,{?MODULE,M10_7,[{{?MODULE,succ,1},M4_4}, - {{?MODULE,seq_r,4},M}, - {{?MODULE,seq,3},M}, - {{?MODULE,'-modules_test/1-fun-3-',1},M_1}, - {{?MODULE,'-modules_test/1-fun-2-',1},M_1}, - {{?MODULE,'-modules_test/1-fun-1-',1},M_1}, - {{?MODULE,'-modules_test/1-fun-0-',1},M_1}, - {{?MODULE,seq_r,3},1}]}} = - lists:keysearch(?MODULE, 1, ModList), - ?line {value,{Module,M2__1,[{{Module,seq_r,4},M}, - {{Module,seq,3},M}, - {{Module,seq_r,3},1}]}} = - lists:keysearch(Module, 1, ModList), - ?line Tot = lists:foldl(fun ({_,C,_}, A) -> C+A end, 0, ModList), - ?line {cprof,_,Prof} = cprof:analyse(cprof), - ?line {value,{{cprof,pause,0},1}} = - lists:keysearch({cprof,pause,0}, 1, Prof), - ?line N = cprof:stop(), + M2 = M*2, + M2__1 = M2 + 1, + erlang:yield(), + N = cprof:start(), + L = Module:seq(1, M, fun succ/1), + Lr = Module:seq_r(1, M, fun succ/1), + L = seq(1, M, fun succ/1), + Lr = seq_r(1, M, fun succ/1), + N = cprof:pause(), + Lr = lists:reverse(L), + M_1 = M - 1, + M4_4 = M*4 - 4, + M10_7 = M*10 - 7, + M2__1 = M*2 + 1, + {Tot,ModList} = cprof:analyse(), + {value,{?MODULE,M10_7,[{{?MODULE,succ,1},M4_4}, + {{?MODULE,seq_r,4},M}, + {{?MODULE,seq,3},M}, + {{?MODULE,'-modules_test/1-fun-3-',1},M_1}, + {{?MODULE,'-modules_test/1-fun-2-',1},M_1}, + {{?MODULE,'-modules_test/1-fun-1-',1},M_1}, + {{?MODULE,'-modules_test/1-fun-0-',1},M_1}, + {{?MODULE,seq_r,3},1}]}} = + lists:keysearch(?MODULE, 1, ModList), + {value,{Module,M2__1,[{{Module,seq_r,4},M}, + {{Module,seq,3},M}, + {{Module,seq_r,3},1}]}} = + lists:keysearch(Module, 1, ModList), + Tot = lists:foldl(fun ({_,C,_}, A) -> C+A end, 0, ModList), + {cprof,_,Prof} = cprof:analyse(cprof), + {value,{{cprof,pause,0},1}} = lists:keysearch({cprof,pause,0}, 1, Prof), + N = cprof:stop(), ok. @@ -302,7 +276,6 @@ modules_test(Config) -> %% Local helpers - %% Stack recursive seq seq(Stop, Stop, Succ) when is_function(Succ) -> [Stop]; @@ -321,6 +294,5 @@ seq_r(Start, Stop, Succ, R) -> seq_r(Succ(Start), Stop, Succ, [Start | R]). - %% Successor succ(X) -> X+1. diff --git a/lib/tools/test/emacs_SUITE.erl b/lib/tools/test/emacs_SUITE.erl index 657a3002a3..77a8813db5 100644 --- a/lib/tools/test/emacs_SUITE.erl +++ b/lib/tools/test/emacs_SUITE.erl @@ -1,18 +1,19 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2013. All Rights Reserved. +%% Copyright Ericsson AB 2005-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% 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 %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% diff --git a/lib/tools/test/emem_SUITE.erl b/lib/tools/test/emem_SUITE.erl index 11fb8bec68..6dca7f6739 100644 --- a/lib/tools/test/emem_SUITE.erl +++ b/lib/tools/test/emem_SUITE.erl @@ -1,32 +1,29 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2011. All Rights Reserved. +%% Copyright Ericsson AB 2005-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% 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 %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% -module(emem_SUITE). -%%-define(line_trace, 1). - --export([init_per_suite/1, end_per_suite/1, +-export([all/0, suite/0, + init_per_testcase/2, end_per_testcase/2, + init_per_suite/1, end_per_suite/1, receive_and_save_trace/2, send_trace/2]). - --export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2, - init_per_testcase/2, end_per_testcase/2]). - -export([live_node/1, 'sparc_sunos5.8_32b_emt2.0'/1, 'pc_win2000_32b_emt2.0'/1, @@ -41,10 +38,7 @@ 'sparc_sunos5.8_64b_emt1.0'/1]). -include_lib("kernel/include/file.hrl"). - --include_lib("test_server/include/test_server.hrl"). - --define(DEFAULT_TIMEOUT, ?t:minutes(5)). +-include_lib("common_test/include/ct.hrl"). -define(EMEM_64_32_COMMENT, "64 bit trace; this build of emem can only handle 32 bit traces"). @@ -61,28 +55,19 @@ exit_code}). %% -%% %% Exported suite functions %% -%% -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,5}}]. all() -> - case is_debug_compiled() of - true -> {skip, "Not run when debug compiled"}; - false -> test_cases() + case test_server:is_debug() of + true -> {skip, "Not run when debug compiled"}; + false -> test_cases() end. -groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - test_cases() -> [live_node, 'sparc_sunos5.8_32b_emt2.0', @@ -98,31 +83,26 @@ test_cases() -> init_per_testcase(Case, Config) when is_list(Config) -> case maybe_skip(Config) of - {skip, _}=Skip -> Skip; + {skip, _}=Skip -> + Skip; ok -> - Dog = ?t:timetrap(?DEFAULT_TIMEOUT), - %% Until emem is completely stable we run these tests in a working %% directory with an ignore_core_files file which will make the %% search for core files ignore cores generated by this suite. - ignore_cores:setup(?MODULE, - Case, - [{watchdog, Dog}, {testcase, Case} | Config]) + ignore_cores:setup(?MODULE, Case, [{testcase, Case}|Config]) end. end_per_testcase(_Case, Config) when is_list(Config) -> ignore_cores:restore(Config), - Dog = ?config(watchdog, Config), - ?t:timetrap_cancel(Dog), ok. maybe_skip(Config) -> - DataDir = ?config(data_dir, Config), + DataDir = proplists:get_value(data_dir, Config), case filelib:is_dir(DataDir) of false -> {skip, "No data directory"}; true -> - case ?config(emem, Config) of + case proplists:get_value(emem, Config) of undefined -> {skip, "emem not found"}; _ -> @@ -158,13 +138,11 @@ end_per_suite(Config) when is_list(Config) -> %% %% -live_node(doc) -> []; -live_node(suite) -> []; live_node(Config) when is_list(Config) -> - ?line {ok, EmuFlag, Port} = start_emem(Config), - ?line Nodename = mk_nodename(Config), - ?line {ok, Node} = start_node(Nodename, EmuFlag), - ?line NP = spawn(Node, + {ok, EmuFlag, Port} = start_emem(Config), + Nodename = mk_nodename(Config), + {ok, Node} = start_node(Nodename, EmuFlag), + NP = spawn(Node, fun () -> receive go -> ok end, I = spawn(fun () -> ignorer end), @@ -186,246 +164,216 @@ live_node(Config) when is_list(Config) -> GC(), GC() end), - ?line MRef = erlang:monitor(process, NP), + MRef = erlang:monitor(process, NP), NP ! go, - ?line receive + receive {'DOWN', MRef, process, NP, Reason} -> - ?line spawn(Node, fun () -> halt(17) end), - ?line normal = Reason + spawn(Node, fun () -> halt(17) end), + normal = Reason end, - ?line Res = get_emem_result(Port), - ?line {ok, Hostname} = inet:gethostname(), - ?line ShortHostname = short_hostname(Hostname), - ?line {true, _} = has_prefix(Nodename, Res#emem_res.nodename), - ?line ShortHostname = short_hostname(Res#emem_res.hostname), - ?line Bits = case erlang:system_info(wordsize) of - 4 -> ?line "32 bits"; - 8 -> ?line "64 bits" + Res = get_emem_result(Port), + {ok, Hostname} = inet:gethostname(), + ShortHostname = short_hostname(Hostname), + {true, _} = has_prefix(Nodename, Res#emem_res.nodename), + ShortHostname = short_hostname(Res#emem_res.hostname), + Bits = case erlang:system_info(wordsize) of + 4 -> "32 bits"; + 8 -> "64 bits" end, - ?line Bits = Res#emem_res.word_size, - ?line "17" = Res#emem_res.exit_code, - ?line emem_comment(Config). + Bits = Res#emem_res.word_size, + "17" = Res#emem_res.exit_code, + emem_comment(Config). -'sparc_sunos5.8_32b_emt2.0'(doc) -> []; -'sparc_sunos5.8_32b_emt2.0'(suite) -> []; 'sparc_sunos5.8_32b_emt2.0'(Config) when is_list(Config) -> - ?line Res = run_emem_on_casefile(Config), - ?line "test_server" = Res#emem_res.nodename, - ?line "gorbag" = Res#emem_res.hostname, - ?line "17074" = Res#emem_res.pid, - ?line "2005-01-14 17:28:37.881980" = Res#emem_res.start_time, - ?line "2.0" = Res#emem_res.trace_version, - ?line "32 bits" = Res#emem_res.word_size, - ?line ["15", - "2665739", "8992", "548986", "16131", "539994", - "4334192", "1", "99", "15", "98", - "0", "0", "49", "0", "49"] = Res#emem_res.last_values, - ?line ["5972061", "9662", - "7987824", "5", - "2375680", "3"] = Res#emem_res.maximum, - ?line "0" = Res#emem_res.exit_code, - ?line emem_comment(Config). - -'pc_win2000_32b_emt2.0'(doc) -> []; -'pc_win2000_32b_emt2.0'(suite) -> []; + Res = run_emem_on_casefile(Config), + "test_server" = Res#emem_res.nodename, + "gorbag" = Res#emem_res.hostname, + "17074" = Res#emem_res.pid, + "2005-01-14 17:28:37.881980" = Res#emem_res.start_time, + "2.0" = Res#emem_res.trace_version, + "32 bits" = Res#emem_res.word_size, + ["15", "2665739", "8992", "548986", "16131", "539994", + "4334192", "1", "99", "15", "98", + "0", "0", "49", "0", "49"] = Res#emem_res.last_values, + ["5972061", "9662", "7987824", "5", + "2375680", "3"] = Res#emem_res.maximum, + "0" = Res#emem_res.exit_code, + emem_comment(Config). + 'pc_win2000_32b_emt2.0'(Config) when is_list(Config) -> - ?line Res = run_emem_on_casefile(Config), - ?line "test_server" = Res#emem_res.nodename, - ?line "E-788FCF5191B54" = Res#emem_res.hostname, - ?line "504" = Res#emem_res.pid, - ?line "2005-01-24 17:27:28.224000" = Res#emem_res.start_time, - ?line "2.0" = Res#emem_res.trace_version, - ?line "32 bits" = Res#emem_res.word_size, - ?line ["11", - "2932575", "8615", "641087", "68924", "632472"] + Res = run_emem_on_casefile(Config), + "test_server" = Res#emem_res.nodename, + "E-788FCF5191B54" = Res#emem_res.hostname, + "504" = Res#emem_res.pid, + "2005-01-24 17:27:28.224000" = Res#emem_res.start_time, + "2.0" = Res#emem_res.trace_version, + "32 bits" = Res#emem_res.word_size, + ["11", "2932575", "8615", "641087", "68924", "632472"] = Res#emem_res.last_values, - ?line ["5434206", "9285"] = Res#emem_res.maximum, - ?line "0" = Res#emem_res.exit_code, - ?line emem_comment(Config). + ["5434206", "9285"] = Res#emem_res.maximum, + "0" = Res#emem_res.exit_code, + emem_comment(Config). -'pc.smp_linux2.2.19pre17_32b_emt2.0'(doc) -> []; -'pc.smp_linux2.2.19pre17_32b_emt2.0'(suite) -> []; 'pc.smp_linux2.2.19pre17_32b_emt2.0'(Config) when is_list(Config) -> - ?line Res = run_emem_on_casefile(Config), - ?line "test_server" = Res#emem_res.nodename, - ?line "four-roses" = Res#emem_res.hostname, - ?line "20689" = Res#emem_res.pid, - ?line "2005-01-20 13:11:26.143077" = Res#emem_res.start_time, - ?line "2.0" = Res#emem_res.trace_version, - ?line "32 bits" = Res#emem_res.word_size, - ?line ["49", - "2901817", "9011", "521610", "10875", "512599", - "5392096", "2", "120", "10", "118", - "0", "0", "59", "0", "59"] = Res#emem_res.last_values, - ?line ["6182918", "9681", - "9062112", "6", - "2322432", "3"] = Res#emem_res.maximum, - ?line "0" = Res#emem_res.exit_code, - ?line emem_comment(Config). - - -'powerpc_darwin7.7.0_32b_emt2.0'(doc) -> []; -'powerpc_darwin7.7.0_32b_emt2.0'(suite) -> []; + Res = run_emem_on_casefile(Config), + "test_server" = Res#emem_res.nodename, + "four-roses" = Res#emem_res.hostname, + "20689" = Res#emem_res.pid, + "2005-01-20 13:11:26.143077" = Res#emem_res.start_time, + "2.0" = Res#emem_res.trace_version, + "32 bits" = Res#emem_res.word_size, + ["49", "2901817", "9011", "521610", "10875", "512599", + "5392096", "2", "120", "10", "118", + "0", "0", "59", "0", "59"] = Res#emem_res.last_values, + ["6182918", "9681", + "9062112", "6", + "2322432", "3"] = Res#emem_res.maximum, + "0" = Res#emem_res.exit_code, + emem_comment(Config). + + 'powerpc_darwin7.7.0_32b_emt2.0'(Config) when is_list(Config) -> - ?line Res = run_emem_on_casefile(Config), - ?line "test_server" = Res#emem_res.nodename, - ?line "grima" = Res#emem_res.hostname, - ?line "13021" = Res#emem_res.pid, - ?line "2005-01-20 15:08:17.568668" = Res#emem_res.start_time, - ?line "2.0" = Res#emem_res.trace_version, - ?line "32 bits" = Res#emem_res.word_size, - ?line ["9", - "2784323", "8641", "531105", "15893", "522464"] + Res = run_emem_on_casefile(Config), + "test_server" = Res#emem_res.nodename, + "grima" = Res#emem_res.hostname, + "13021" = Res#emem_res.pid, + "2005-01-20 15:08:17.568668" = Res#emem_res.start_time, + "2.0" = Res#emem_res.trace_version, + "32 bits" = Res#emem_res.word_size, + ["9", "2784323", "8641", "531105", "15893", "522464"] = Res#emem_res.last_values, - ?line ["6150376", "9311"] = Res#emem_res.maximum, - ?line "0" = Res#emem_res.exit_code, - ?line emem_comment(Config). + ["6150376", "9311"] = Res#emem_res.maximum, + "0" = Res#emem_res.exit_code, + emem_comment(Config). -'alpha_osf1v5.1_64b_emt2.0'(doc) -> []; -'alpha_osf1v5.1_64b_emt2.0'(suite) -> []; 'alpha_osf1v5.1_64b_emt2.0'(Config) when is_list(Config) -> - ?line Res = run_emem_on_casefile(Config), - ?line "test_server" = Res#emem_res.nodename, - ?line "thorin" = Res#emem_res.hostname, - ?line "224630" = Res#emem_res.pid, - ?line "2005-01-20 22:38:01.299632" = Res#emem_res.start_time, - ?line "2.0" = Res#emem_res.trace_version, - ?line "64 bits" = Res#emem_res.word_size, - ?line case Res#emem_res.max_word_size of - "32 bits" -> - ?line emem_comment(Config, ?EMEM_64_32_COMMENT); - "64 bits" -> - ?line ["22", - "6591992", "8625", "516785", "14805", "508160", - "11429184", "5", "127", "254", "122", - "0", "0", "61", "0", "61"] = Res#emem_res.last_values, - ?line ["7041775", "9295", - "11593024", "7", - "2097152", "3"] = Res#emem_res.maximum, - ?line "0" = Res#emem_res.exit_code, - ?line emem_comment(Config) - end. - -'sparc_sunos5.8_64b_emt2.0'(doc) -> []; -'sparc_sunos5.8_64b_emt2.0'(suite) -> []; + Res = run_emem_on_casefile(Config), + "test_server" = Res#emem_res.nodename, + "thorin" = Res#emem_res.hostname, + "224630" = Res#emem_res.pid, + "2005-01-20 22:38:01.299632" = Res#emem_res.start_time, + "2.0" = Res#emem_res.trace_version, + "64 bits" = Res#emem_res.word_size, + case Res#emem_res.max_word_size of + "32 bits" -> + emem_comment(Config, ?EMEM_64_32_COMMENT); + "64 bits" -> + ["22", + "6591992", "8625", "516785", "14805", "508160", + "11429184", "5", "127", "254", "122", + "0", "0", "61", "0", "61"] = Res#emem_res.last_values, + ["7041775", "9295", + "11593024", "7", + "2097152", "3"] = Res#emem_res.maximum, + "0" = Res#emem_res.exit_code, + emem_comment(Config) + end. + 'sparc_sunos5.8_64b_emt2.0'(Config) when is_list(Config) -> - ?line Res = run_emem_on_casefile(Config), - ?line "test_server" = Res#emem_res.nodename, - ?line "gorbag" = Res#emem_res.hostname, - ?line "10907" = Res#emem_res.pid, - ?line "2005-01-20 13:48:34.677068" = Res#emem_res.start_time, - ?line "2.0" = Res#emem_res.trace_version, - ?line "64 bits" = Res#emem_res.word_size, - ?line case Res#emem_res.max_word_size of - "32 bits" -> - ?line emem_comment(Config, ?EMEM_64_32_COMMENT); - "64 bits" -> - ?line ["16", - "5032887", "8657", "530635", "14316", "521978", - "8627140", "5", "139", "19", "134", - "0", "0", "67", "0", "67"] = Res#emem_res.last_values, - ?line ["11695070", "9324", - "16360388", "10", - "4136960", "3"] = Res#emem_res.maximum, - ?line "0" = Res#emem_res.exit_code, - ?line emem_comment(Config) - end. - -'sparc_sunos5.8_32b_emt1.0'(doc) -> []; -'sparc_sunos5.8_32b_emt1.0'(suite) -> []; + Res = run_emem_on_casefile(Config), + "test_server" = Res#emem_res.nodename, + "gorbag" = Res#emem_res.hostname, + "10907" = Res#emem_res.pid, + "2005-01-20 13:48:34.677068" = Res#emem_res.start_time, + "2.0" = Res#emem_res.trace_version, + "64 bits" = Res#emem_res.word_size, + case Res#emem_res.max_word_size of + "32 bits" -> + emem_comment(Config, ?EMEM_64_32_COMMENT); + "64 bits" -> + ["16", + "5032887", "8657", "530635", "14316", "521978", + "8627140", "5", "139", "19", "134", + "0", "0", "67", "0", "67"] = Res#emem_res.last_values, + ["11695070", "9324", + "16360388", "10", + "4136960", "3"] = Res#emem_res.maximum, + "0" = Res#emem_res.exit_code, + emem_comment(Config) + end. + 'sparc_sunos5.8_32b_emt1.0'(Config) when is_list(Config) -> - ?line Res = run_emem_on_casefile(Config), - ?line "" = Res#emem_res.nodename, - ?line "" = Res#emem_res.hostname, - ?line "" = Res#emem_res.pid, - ?line "" = Res#emem_res.start_time, - ?line "1.0" = Res#emem_res.trace_version, - ?line "32 bits" = Res#emem_res.word_size, - ?line ["11", - "2558261", "8643", "560610", "15325", "551967"] + Res = run_emem_on_casefile(Config), + "" = Res#emem_res.nodename, + "" = Res#emem_res.hostname, + "" = Res#emem_res.pid, + "" = Res#emem_res.start_time, + "1.0" = Res#emem_res.trace_version, + "32 bits" = Res#emem_res.word_size, + ["11", "2558261", "8643", "560610", "15325", "551967"] = Res#emem_res.last_values, - ?line ["2791121", "9317"] = Res#emem_res.maximum, - ?line "0" = Res#emem_res.exit_code, - ?line emem_comment(Config). + ["2791121", "9317"] = Res#emem_res.maximum, + "0" = Res#emem_res.exit_code, + emem_comment(Config). -'pc_win2000_32b_emt1.0'(doc) -> []; -'pc_win2000_32b_emt1.0'(suite) -> []; 'pc_win2000_32b_emt1.0'(Config) when is_list(Config) -> - ?line Res = run_emem_on_casefile(Config), - ?line "" = Res#emem_res.nodename, - ?line "" = Res#emem_res.hostname, - ?line "" = Res#emem_res.pid, - ?line "" = Res#emem_res.start_time, - ?line "1.0" = Res#emem_res.trace_version, - ?line "32 bits" = Res#emem_res.word_size, - ?line ["6", - "2965248", "8614", "640897", "68903", "632283"] + Res = run_emem_on_casefile(Config), + "" = Res#emem_res.nodename, + "" = Res#emem_res.hostname, + "" = Res#emem_res.pid, + "" = Res#emem_res.start_time, + "1.0" = Res#emem_res.trace_version, + "32 bits" = Res#emem_res.word_size, + ["6", "2965248", "8614", "640897", "68903", "632283"] = Res#emem_res.last_values, - ?line ["3147090", "9283"] = Res#emem_res.maximum, - ?line "0" = Res#emem_res.exit_code, - ?line emem_comment(Config). + ["3147090", "9283"] = Res#emem_res.maximum, + "0" = Res#emem_res.exit_code, + emem_comment(Config). -'powerpc_darwin7.7.0_32b_emt1.0'(doc) -> []; -'powerpc_darwin7.7.0_32b_emt1.0'(suite) -> []; 'powerpc_darwin7.7.0_32b_emt1.0'(Config) when is_list(Config) -> - ?line Res = run_emem_on_casefile(Config), - ?line "" = Res#emem_res.nodename, - ?line "" = Res#emem_res.hostname, - ?line "" = Res#emem_res.pid, - ?line "" = Res#emem_res.start_time, - ?line "1.0" = Res#emem_res.trace_version, - ?line "32 bits" = Res#emem_res.word_size, - ?line ["8", - "2852991", "8608", "529662", "15875", "521054"] + Res = run_emem_on_casefile(Config), + "" = Res#emem_res.nodename, + "" = Res#emem_res.hostname, + "" = Res#emem_res.pid, + "" = Res#emem_res.start_time, + "1.0" = Res#emem_res.trace_version, + "32 bits" = Res#emem_res.word_size, + ["8", "2852991", "8608", "529662", "15875", "521054"] = Res#emem_res.last_values, - ?line ["3173335", "9278"] = Res#emem_res.maximum, - ?line "0" = Res#emem_res.exit_code, - ?line emem_comment(Config). + ["3173335", "9278"] = Res#emem_res.maximum, + "0" = Res#emem_res.exit_code, + emem_comment(Config). -'alpha_osf1v5.1_64b_emt1.0'(doc) -> []; -'alpha_osf1v5.1_64b_emt1.0'(suite) -> []; 'alpha_osf1v5.1_64b_emt1.0'(Config) when is_list(Config) -> - ?line Res = run_emem_on_casefile(Config), - ?line "" = Res#emem_res.nodename, - ?line "" = Res#emem_res.hostname, - ?line "" = Res#emem_res.pid, - ?line "" = Res#emem_res.start_time, - ?line "1.0" = Res#emem_res.trace_version, - ?line "64 bits" = Res#emem_res.word_size, - ?line case Res#emem_res.max_word_size of - "32 bits" -> - ?line emem_comment(Config, ?EMEM_64_32_COMMENT); - "64 bits" -> - ?line ["22", - "6820094", "8612", "515518", "14812", "506906"] - = Res#emem_res.last_values, - ?line ["7292413", "9282"] = Res#emem_res.maximum, - ?line "0" = Res#emem_res.exit_code, - ?line emem_comment(Config) - end. - -'sparc_sunos5.8_64b_emt1.0'(doc) -> []; -'sparc_sunos5.8_64b_emt1.0'(suite) -> []; + Res = run_emem_on_casefile(Config), + "" = Res#emem_res.nodename, + "" = Res#emem_res.hostname, + "" = Res#emem_res.pid, + "" = Res#emem_res.start_time, + "1.0" = Res#emem_res.trace_version, + "64 bits" = Res#emem_res.word_size, + case Res#emem_res.max_word_size of + "32 bits" -> + emem_comment(Config, ?EMEM_64_32_COMMENT); + "64 bits" -> + ["22", + "6820094", "8612", "515518", "14812", "506906"] + = Res#emem_res.last_values, + ["7292413", "9282"] = Res#emem_res.maximum, + "0" = Res#emem_res.exit_code, + emem_comment(Config) + end. + 'sparc_sunos5.8_64b_emt1.0'(Config) when is_list(Config) -> - ?line Res = run_emem_on_casefile(Config), - ?line "" = Res#emem_res.nodename, - ?line "" = Res#emem_res.hostname, - ?line "" = Res#emem_res.pid, - ?line "" = Res#emem_res.start_time, - ?line "1.0" = Res#emem_res.trace_version, - ?line "64 bits" = Res#emem_res.word_size, - ?line case Res#emem_res.max_word_size of - "32 bits" -> - ?line emem_comment(Config, ?EMEM_64_32_COMMENT); - "64 bits" -> - ?line ["15", - "4965746", "8234", "543940", "14443", "535706"] - = Res#emem_res.last_values, - ?line ["11697645", "8908"] = Res#emem_res.maximum, - ?line "0" = Res#emem_res.exit_code, - ?line emem_comment(Config) - end. + Res = run_emem_on_casefile(Config), + "" = Res#emem_res.nodename, + "" = Res#emem_res.hostname, + "" = Res#emem_res.pid, + "" = Res#emem_res.start_time, + "1.0" = Res#emem_res.trace_version, + "64 bits" = Res#emem_res.word_size, + case Res#emem_res.max_word_size of + "32 bits" -> + emem_comment(Config, ?EMEM_64_32_COMMENT); + "64 bits" -> + ["15", + "4965746", "8234", "543940", "14443", "535706"] + = Res#emem_res.last_values, + ["11697645", "8908"] = Res#emem_res.maximum, + "0" = Res#emem_res.exit_code, + emem_comment(Config) + end. %% %% @@ -443,84 +391,84 @@ receive_and_save_trace(PortNumber, FileName) when is_integer(PortNumber), receive_loop(Socket, File) -> receive - {tcp, Socket, Data} -> - ok = file:write(File, Data), - receive_loop(Socket, File); - {tcp_closed, Socket} -> - file:close(File), - ok; - {tcp_error, Socket, Reason} -> - file:close(File), - {error, Reason} + {tcp, Socket, Data} -> + ok = file:write(File, Data), + receive_loop(Socket, File); + {tcp_closed, Socket} -> + file:close(File), + ok; + {tcp_error, Socket, Reason} -> + file:close(File), + {error, Reason} end. send_trace({Host, PortNumber}, FileName) when is_list(Host), is_integer(PortNumber), is_list(FileName) -> - ?line {ok, F} = file:open(FileName, [read, compressed]), - ?line {ok, S} = gen_tcp:connect(Host, PortNumber, [inet,{packet, 0}]), - ?line send_loop(S, F); + {ok, F} = file:open(FileName, [read, compressed]), + {ok, S} = gen_tcp:connect(Host, PortNumber, [inet,{packet, 0}]), + send_loop(S, F); send_trace(EmuFlag, FileName) when is_list(EmuFlag), is_list(FileName) -> - ?line ["+Mit", IpAddrStr, PortNoStr] = string:tokens(EmuFlag, " :"), - ?line send_trace({IpAddrStr, list_to_integer(PortNoStr)}, FileName). + ["+Mit", IpAddrStr, PortNoStr] = string:tokens(EmuFlag, " :"), + send_trace({IpAddrStr, list_to_integer(PortNoStr)}, FileName). send_loop(Socket, File) -> - ?line case file:read(File, 128) of - {ok, Data} -> - ?line case gen_tcp:send(Socket, Data) of - ok -> ?line send_loop(Socket, File); - Error -> - ?line gen_tcp:close(Socket), - ?line file:close(File), - Error - end; - eof -> - ?line gen_tcp:close(Socket), - ?line file:close(File), - ?line ok; - Error -> - ?line gen_tcp:close(Socket), - ?line file:close(File), - ?line Error - end. + case file:read(File, 128) of + {ok, Data} -> + case gen_tcp:send(Socket, Data) of + ok -> send_loop(Socket, File); + Error -> + gen_tcp:close(Socket), + file:close(File), + Error + end; + eof -> + gen_tcp:close(Socket), + file:close(File), + ok; + Error -> + gen_tcp:close(Socket), + file:close(File), + Error + end. check_emem(Dir, Type) when is_atom(Type) -> - ExeSuffix = case ?t:os_type() of - {win32, _} -> ".exe"; - _ -> "" - end, + ExeSuffix = case os:type() of + {win32, _} -> ".exe"; + _ -> "" + end, TypeSuffix = case Type of - opt -> ""; - _ -> "." ++ atom_to_list(Type) - end, + opt -> ""; + _ -> "." ++ atom_to_list(Type) + end, Emem = "emem" ++ TypeSuffix ++ ExeSuffix, case check_file(filename:join([Dir, Emem])) of - not_found -> ok; - File -> - Comment = case Type of - opt -> ""; - _ -> "[emem " ++ atom_to_list(Type) ++ " compiled]" - end, - throw([{emem, File}, {emem_comment, Comment}]) + not_found -> ok; + File -> + Comment = case Type of + opt -> ""; + _ -> "[emem " ++ atom_to_list(Type) ++ " compiled]" + end, + throw([{emem, File}, {emem_comment, Comment}]) end. check_dir(DirName) -> case file:read_file_info(DirName) of - {ok, #file_info {type = directory, access = A}} when A == read; - A == read_write -> - DirName; - _ -> - not_found + {ok, #file_info {type = directory, access = A}} when A == read; + A == read_write -> + DirName; + _ -> + not_found end. check_file(FileName) -> case file:read_file_info(FileName) of - {ok, #file_info {type = regular, access = A}} when A == read; - A == read_write -> - ?line FileName; - _ -> - ?line not_found + {ok, #file_info {type = regular, access = A}} when A == read; + A == read_write -> + FileName; + _ -> + not_found end. emem_comment(Config) when is_list(Config) -> @@ -528,158 +476,158 @@ emem_comment(Config) when is_list(Config) -> emem_comment(Config, ExtraComment) when is_list(Config), is_list(ExtraComment) -> - case {?config(emem_comment, Config), ExtraComment} of - {"", ""} -> ?line ok; - {"", XC} -> ?line {comment, XC}; - {EmemC, ""} -> ?line {comment, EmemC}; - {EmemC, XC} -> ?line {comment, EmemC ++ " " ++ XC} + case {proplists:get_value(emem_comment, Config), ExtraComment} of + {"", ""} -> ok; + {"", XC} -> {comment, XC}; + {EmemC, ""} -> {comment, EmemC}; + {EmemC, XC} -> {comment, EmemC ++ " " ++ XC} end. run_emem_on_casefile(Config) -> - CaseName = atom_to_list(?config(testcase, Config)), - ?line File = filename:join([?config(data_dir, Config), CaseName ++ ".gz"]), - ?line case check_file(File) of - not_found -> - ?line ?t:fail({error, {filenotfound, File}}); - _ -> - ?line ok - end, - ?line {ok, EmuFlag, Port} = start_emem(Config), - ?line Parent = self(), - ?line Ref = make_ref(), - ?line spawn_link(fun () -> - SRes = send_trace(EmuFlag, File), - Parent ! {Ref, SRes} - end), - ?line Res = get_emem_result(Port), - ?line receive - {Ref, ok} -> - ?line ok; - {Ref, SendError} -> - ?line ?t:format("Send result: ~p~n", [SendError]) - end, - ?line Res. + CaseName = atom_to_list(proplists:get_value(testcase, Config)), + File = filename:join([proplists:get_value(data_dir, Config), CaseName ++ ".gz"]), + case check_file(File) of + not_found -> + ct:fail({error, {filenotfound, File}}); + _ -> + ok + end, + {ok, EmuFlag, Port} = start_emem(Config), + Parent = self(), + Ref = make_ref(), + spawn_link(fun () -> + SRes = send_trace(EmuFlag, File), + Parent ! {Ref, SRes} + end), + Res = get_emem_result(Port), + receive + {Ref, ok} -> + ok; + {Ref, SendError} -> + io:format("Send result: ~p~n", [SendError]) + end, + Res. get_emem_result(Port) -> - ?line {Res, LV} = get_emem_result(Port, {#emem_res{}, []}), - ?line Res#emem_res{last_values = string:tokens(LV, " ")}. + {Res, LV} = get_emem_result(Port, {#emem_res{}, []}), + Res#emem_res{last_values = string:tokens(LV, " ")}. get_emem_result(Port, {_EmemRes, _LastValues} = Res) -> - ?line case get_emem_line(Port) of - eof -> - ?line Res; - Line -> - ?line get_emem_result(Port, parse_emem_line(Line, Res)) - end. + case get_emem_line(Port) of + eof -> + Res; + Line -> + get_emem_result(Port, parse_emem_line(Line, Res)) + end. parse_emem_main_header_footer_line(Line, {ER, LV} = Res) -> %% Header - ?line case has_prefix("> Nodename:", Line) of - {true, NN} -> - ?line throw({ER#emem_res{nodename = strip(NN)}, LV}); - false -> ?line ok - end, - ?line case has_prefix("> Hostname:", Line) of - {true, HN} -> - ?line throw({ER#emem_res{hostname = strip(HN)}, LV}); - false -> ?line ok - end, - ?line case has_prefix("> Pid:", Line) of - {true, P} -> - ?line throw({ER#emem_res{pid = strip(P)}, LV}); - false -> ?line ok - end, - ?line case has_prefix("> Start time (UTC):", Line) of - {true, ST} -> - ?line throw({ER#emem_res{start_time = strip(ST)}, LV}); - false -> ?line ok - end, - ?line case has_prefix("> Actual trace version:", Line) of - {true, TV} -> - ?line throw({ER#emem_res{trace_version = strip(TV)}, LV}); - false -> ?line ok - end, - ?line case has_prefix("> Maximum trace word size:", Line) of - {true, MWS} -> - ?line throw({ER#emem_res{max_word_size = strip(MWS)}, LV}); - false -> ?line ok - end, - ?line case has_prefix("> Actual trace word size:", Line) of - {true, WS} -> - ?line throw({ER#emem_res{word_size = strip(WS)}, LV}); - false -> ?line ok - end, + case has_prefix("> Nodename:", Line) of + {true, NN} -> + throw({ER#emem_res{nodename = strip(NN)}, LV}); + false -> ok + end, + case has_prefix("> Hostname:", Line) of + {true, HN} -> + throw({ER#emem_res{hostname = strip(HN)}, LV}); + false -> ok + end, + case has_prefix("> Pid:", Line) of + {true, P} -> + throw({ER#emem_res{pid = strip(P)}, LV}); + false -> ok + end, + case has_prefix("> Start time (UTC):", Line) of + {true, ST} -> + throw({ER#emem_res{start_time = strip(ST)}, LV}); + false -> ok + end, + case has_prefix("> Actual trace version:", Line) of + {true, TV} -> + throw({ER#emem_res{trace_version = strip(TV)}, LV}); + false -> ok + end, + case has_prefix("> Maximum trace word size:", Line) of + {true, MWS} -> + throw({ER#emem_res{max_word_size = strip(MWS)}, LV}); + false -> ok + end, + case has_prefix("> Actual trace word size:", Line) of + {true, WS} -> + throw({ER#emem_res{word_size = strip(WS)}, LV}); + false -> ok + end, %% Footer - ?line case has_prefix("> Maximum:", Line) of - {true, M} -> - ?line throw({ER#emem_res{maximum = string:tokens(M," ")}, LV}); - false -> ?line ok - end, - ?line case has_prefix("> Emulator exited with code:", Line) of - {true, EC} -> - ?line throw({ER#emem_res{exit_code = strip(EC)}, LV}); - false -> ?line ok - end, - ?line Res. + case has_prefix("> Maximum:", Line) of + {true, M} -> + throw({ER#emem_res{maximum = string:tokens(M," ")}, LV}); + false -> ok + end, + case has_prefix("> Emulator exited with code:", Line) of + {true, EC} -> + throw({ER#emem_res{exit_code = strip(EC)}, LV}); + false -> ok + end, + Res. parse_emem_header_line(_Line, {_ER, _LV} = Res) -> - ?line Res. - + Res. + parse_emem_value_line(Line, {EmemRes, _OldLastValues}) -> - ?line {EmemRes, Line}. + {EmemRes, Line}. parse_emem_line("", Res) -> - ?line Res; + Res; parse_emem_line(Line, Res) -> - ?line [Prefix | _] = Line, + [Prefix | _] = Line, case Prefix of - $> -> ?line catch parse_emem_main_header_footer_line(Line, Res); - $| -> ?line catch parse_emem_header_line(Line, Res); - _ -> ?line catch parse_emem_value_line(Line, Res) + $> -> catch parse_emem_main_header_footer_line(Line, Res); + $| -> catch parse_emem_header_line(Line, Res); + _ -> catch parse_emem_value_line(Line, Res) end. start_emem(Config) when is_list(Config) -> - ?line Emem = ?config(emem, Config), - ?line Cd = case ignore_cores:dir(Config) of - false -> []; - Dir -> [{cd, Dir}] - end, - ?line case open_port({spawn, Emem ++ " -t -n -o -i 1"}, - Cd ++ [{line, 1024}, eof]) of - Port when is_port(Port) -> ?line {ok, read_emu_flag(Port), Port}; - Error -> ?line ?t:fail(Error) - end. + Emem = proplists:get_value(emem, Config), + Cd = case ignore_cores:dir(Config) of + false -> []; + Dir -> [{cd, Dir}] + end, + case open_port({spawn, Emem ++ " -t -n -o -i 1"}, + Cd ++ [{line, 1024}, eof]) of + Port when is_port(Port) -> {ok, read_emu_flag(Port), Port}; + Error -> ct:fail(Error) + end. read_emu_flag(Port) -> - ?line Line = case get_emem_line(Port) of - eof -> ?line ?t:fail(unexpected_end_of_file); - L -> ?line L - end, - ?line case has_prefix("> Emulator command line argument:", Line) of - {true, EmuFlag} -> EmuFlag; - false -> ?line read_emu_flag(Port) - end. + Line = case get_emem_line(Port) of + eof -> ct:fail(unexpected_end_of_file); + L -> L + end, + case has_prefix("> Emulator command line argument:", Line) of + {true, EmuFlag} -> EmuFlag; + false -> read_emu_flag(Port) + end. get_emem_line(Port, Acc) -> - ?line receive - {Port, {data, {eol, Data}}} -> - ?line Res = case Acc of - [] -> ?line Data; - _ -> ?line lists:flatten([Acc|Data]) - end, - ?line ?t:format("~s", [Res]), - ?line Res; - {Port, {data, {noeol, Data}}} -> - ?line get_emem_line(Port, [Acc|Data]); - {Port, eof} -> - ?line port_close(Port), - ?line eof - end. + receive + {Port, {data, {eol, Data}}} -> + Res = case Acc of + [] -> Data; + _ -> lists:flatten([Acc|Data]) + end, + io:format("~s", [Res]), + Res; + {Port, {data, {noeol, Data}}} -> + get_emem_line(Port, [Acc|Data]); + {Port, eof} -> + port_close(Port), + eof + end. get_emem_line(Port) -> - ?line get_emem_line(Port, []). + get_emem_line(Port, []). short_hostname([]) -> []; @@ -696,28 +644,13 @@ has_prefix(_, _) -> false. strip(Str) -> string:strip(Str). - + mk_nodename(Config) -> - {A, B, C} = now(), + Us = erlang:monotonic_time(), atom_to_list(?MODULE) - ++ "-" ++ atom_to_list(?config(testcase, Config)) - ++ "-" ++ integer_to_list(A*1000000000000 + B*1000000 + C). + ++ "-" ++ atom_to_list(proplists:get_value(testcase, Config)) + ++ integer_to_list(Us). start_node(Name, Args) -> - ?line Pa = filename:dirname(code:which(?MODULE)), - ?line ?t:start_node(Name, peer, [{args, Args ++ " -pa " ++ Pa}]). - -% stop_node(Node) -> -% ?t:stop_node(Node). - -is_debug_compiled() -> -is_debug_compiled(erlang:system_info(system_version)). - -is_debug_compiled([$d,$e,$b,$u,$g | _]) -> - true; -is_debug_compiled([ _, _, _, _]) -> - false; -is_debug_compiled([]) -> - false; -is_debug_compiled([_|Rest]) -> - is_debug_compiled(Rest). + Pa = filename:dirname(code:which(?MODULE)), + test_server:start_node(Name, peer, [{args, Args ++ " -pa " ++ Pa}]). diff --git a/lib/tools/test/eprof_SUITE.erl b/lib/tools/test/eprof_SUITE.erl index 04b522de4a..e908413315 100644 --- a/lib/tools/test/eprof_SUITE.erl +++ b/lib/tools/test/eprof_SUITE.erl @@ -1,59 +1,43 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% 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 %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% -module(eprof_SUITE). --include_lib("test_server/include/test_server.hrl"). - --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2]). +-include_lib("common_test/include/ct.hrl"). +-export([all/0, suite/0]). -export([tiny/1,eed/1,basic/1,basic_option/1]). -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap,{seconds,60}}]. all() -> [basic, basic_option, tiny, eed]. -groups() -> - []. - -init_per_suite(Config) -> - Config. - -end_per_suite(_Config) -> - ok. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -basic(suite) -> []; basic(Config) when is_list(Config) -> %% load eprof_test and change directory {ok, OldCurDir} = file:get_cwd(), - Datadir = ?config(data_dir, Config), - Privdir = ?config(priv_dir, Config), + Datadir = proplists:get_value(data_dir, Config), + Privdir = proplists:get_value(priv_dir, Config), {ok,eprof_test} = compile:file(filename:join(Datadir, "eprof_test"), [trace,{outdir, Privdir}]), ok = file:set_cwd(Privdir), @@ -97,9 +81,6 @@ basic(Config) when is_list(Config) -> %% error case - error = eprof:profile([Pid], fun() -> eprof_test:go(10) end), - Pid = whereis(eprof), - error = eprof:profile([Pid], fun() -> eprof_test:go(10) end), A = spawn(fun() -> receive _ -> ok end end), profiling = eprof:profile([A]), true = exit(A, kill_it), @@ -138,8 +119,8 @@ basic_option_1(Config) -> %% load eprof_test and change directory {ok, OldCurDir} = file:get_cwd(), - Datadir = ?config(data_dir, Config), - Privdir = ?config(priv_dir, Config), + Datadir = proplists:get_value(data_dir, Config), + Privdir = proplists:get_value(priv_dir, Config), {ok,eprof_test} = compile:file(filename:join(Datadir, "eprof_test"), [trace,{outdir, Privdir}]), ok = file:set_cwd(Privdir), @@ -177,13 +158,11 @@ basic_option_1(Config) -> stopped = eprof:stop(), ok. -tiny(suite) -> []; tiny(Config) when is_list(Config) -> ensure_eprof_stopped(), {ok, OldCurDir} = file:get_cwd(), - Datadir = ?config(data_dir, Config), - Privdir = ?config(priv_dir, Config), - TTrap=?t:timetrap(60*1000), + Datadir = proplists:get_value(data_dir, Config), + Privdir = proplists:get_value(priv_dir, Config), % (Trace)Compile to priv_dir and make sure the correct version is loaded. {ok,eprof_suite_test} = compile:file(filename:join(Datadir, "eprof_suite_test"), @@ -199,16 +178,14 @@ tiny(Config) when is_list(Config) -> ok = eprof:analyze(total), ok = eprof:log("eprof_SUITE_logfile"), stopped = eprof:stop(), - ?t:timetrap_cancel(TTrap), ok = file:set_cwd(OldCurDir), ok. -eed(suite) -> []; eed(Config) when is_list(Config) -> ensure_eprof_stopped(), - Datadir = ?config(data_dir, Config), - Privdir = ?config(priv_dir, Config), - TTrap=?t:timetrap(5*60*1000), + Datadir = proplists:get_value(data_dir, Config), + Privdir = proplists:get_value(priv_dir, Config), + ct:timetrap({minutes, 5}), %% (Trace)Compile to priv_dir and make sure the correct version is loaded. code:purge(eed), @@ -235,7 +212,6 @@ eed(Config) when is_list(Config) -> ok = eprof:analyze(total), ok = eprof:log("eprof_SUITE_logfile"), stopped = eprof:stop(), - ?t:timetrap_cancel(TTrap), try S = lists:flatten(io_lib:format("~p times slower", [10*(T3-T2)/(T2-T1)])), diff --git a/lib/tools/test/eprof_SUITE_data/eprof_suite_test.erl b/lib/tools/test/eprof_SUITE_data/eprof_suite_test.erl index a88b6e21f2..4e0c4d3118 100644 --- a/lib/tools/test/eprof_SUITE_data/eprof_suite_test.erl +++ b/lib/tools/test/eprof_SUITE_data/eprof_suite_test.erl @@ -1,13 +1,14 @@ -%% ``The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved via the world wide web at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% ``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. %% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB. %% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings diff --git a/lib/tools/test/fprof_SUITE.erl b/lib/tools/test/fprof_SUITE.erl index 1bc4c11b5d..affb45b7a6 100644 --- a/lib/tools/test/fprof_SUITE.erl +++ b/lib/tools/test/fprof_SUITE.erl @@ -1,45 +1,41 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2012. All Rights Reserved. +%% Copyright Ericsson AB 2001-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% 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 %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% -module(fprof_SUITE). --include_lib("test_server/include/test_server.hrl"). +-include_lib("common_test/include/ct.hrl"). %% Test server framework exports --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2, not_run/1]). +-export([all/0, suite/0, not_run/1]). %% Test suites -export([stack_seq/1, tail_seq/1, create_file_slow/1, spawn_simple/1, - imm_tail_seq/1, imm_create_file_slow/1, imm_compile/1, - cpu_create_file_slow/1]). + imm_tail_seq/1, imm_create_file_slow/1, imm_compile/1, + cpu_create_file_slow/1]). %% Other exports -export([create_file_slow/2]). - %% Debug exports -export([parse/1, verify/2]). -export([spawn_simple_test/3]). - --define(line_trace,true). - %-define(debug,true). -ifdef(debug). -define(dbg(Str,Args), io:format(Str,Args)). @@ -48,553 +44,495 @@ -endif. - %%%--------------------------------------------------------------------- %%% Test suites %%%--------------------------------------------------------------------- - -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap,{seconds,60}}]. all() -> case test_server:is_native(fprof_SUITE) of - true -> [not_run]; - false -> - [stack_seq, tail_seq, create_file_slow, spawn_simple, - imm_tail_seq, imm_create_file_slow, imm_compile, - cpu_create_file_slow] + true -> [not_run]; + false -> + [stack_seq, tail_seq, create_file_slow, spawn_simple, + imm_tail_seq, imm_create_file_slow, imm_compile, + cpu_create_file_slow] end. -groups() -> - []. - -init_per_suite(Config) -> - Config. - -end_per_suite(_Config) -> - ok. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - not_run(Config) when is_list(Config) -> {skipped, "Native code"}. %%%--------------------------------------------------------------------- -stack_seq(doc) -> - ["Tests a stack recursive variant of lists:seq/3"]; -stack_seq(suite) -> - []; +%% Tests a stack recursive variant of lists:seq/3 stack_seq(Config) when is_list(Config) -> - ?line Timetrap = ?t:timetrap(?t:seconds(20)), - ?line PrivDir = ?config(priv_dir, Config), - ?line TraceFile = - filename:join(PrivDir, ?MODULE_STRING"_stack_seq.trace"), - ?line AnalysisFile = - filename:join(PrivDir, ?MODULE_STRING"_stack_seq.analysis"), - ?line Start = 1, - ?line Stop = 1000, - ?line Succ = fun (X) -> X + 1 end, - ?line ok = fprof:stop(kill), + PrivDir = proplists:get_value(priv_dir, Config), + TraceFile = filename:join(PrivDir, + ?MODULE_STRING"_stack_seq.trace"), + AnalysisFile = filename:join(PrivDir, + ?MODULE_STRING"_stack_seq.analysis"), + Start = 1, + Stop = 1000, + Succ = fun (X) -> X + 1 end, + ok = fprof:stop(kill), %% - ?line TS0 = erlang:now(), - ?line R0 = fprof:apply(fun seq/3, [Start, Stop, Succ], [{file, TraceFile}]), - ?line TS1 = erlang:now(), - ?line R = seq(Start, Stop, Succ), - ?line TS2 = erlang:now(), - ?line ok = fprof:profile(file, TraceFile), - ?line ok = fprof:analyse(), - ?line ok = fprof:analyse(dest, AnalysisFile), - ?line ok = fprof:stop(), - ?line R = R0, + TS0 = erlang:monotonic_time(), + R0 = fprof:apply(fun seq/3, [Start, Stop, Succ], [{file, TraceFile}]), + TS1 = erlang:monotonic_time(), + R = seq(Start, Stop, Succ), + TS2 = erlang:monotonic_time(), + ok = fprof:profile(file, TraceFile), + ok = fprof:analyse(), + ok = fprof:analyse(dest, AnalysisFile), + ok = fprof:stop(), + R = R0, %% - ?line {ok, [T, P]} = parse(AnalysisFile), - ?line io:format("~p~n~n~p~n", [P, ets:tab2list(T)]), - ?line ok = (catch verify(T, P)), - ?line Proc = pid_to_list(self()), - ?line case P of - [{analysis_options, _}, - [{totals, _, Acc, _}], - [{Proc, _, undefined, _} | _]] -> - ok - end, + {ok, [T, P]} = parse(AnalysisFile), + io:format("~p~n~n~p~n", [P, ets:tab2list(T)]), + ok = (catch verify(T, P)), + Proc = pid_to_list(self()), + case P of + [{analysis_options, _}, + [{totals, _, Acc, _}], + [{Proc, _, undefined, _} | _]] -> + ok + end, %% - ?line check_own_and_acc(TraceFile,AnalysisFile), + check_own_and_acc(TraceFile,AnalysisFile), %% - ?line ets:delete(T), - ?line file:delete(TraceFile), - ?line file:delete(AnalysisFile), - ?line ?t:timetrap_cancel(Timetrap), - ?line Acc1 = ts_sub(TS1, TS0), - ?line Acc2 = ts_sub(TS2, TS1), - ?line io:format("ts:~w, fprof:~w, bare:~w.~n", [Acc, Acc1, Acc2]), - {comment, io_lib:format("~p times slower", [Acc1/Acc2])}. + ets:delete(T), + file:delete(TraceFile), + file:delete(AnalysisFile), + Acc1 = TS1 - TS0, + Acc2 = TS2 - TS1, + io:format("ts:~w, fprof:~w, bare:~w.~n", [Acc, Acc1, Acc2]), + {comment, io_lib:format("~p times slower", [divide(Acc1,Acc2)])}. %%%--------------------------------------------------------------------- -tail_seq(doc) -> - ["Tests a tail recursive variant of lists:seq/3"]; -tail_seq(suite) -> - []; +%% Tests a tail recursive variant of lists:seq/3 tail_seq(Config) when is_list(Config) -> - ?line Timetrap = ?t:timetrap(?t:seconds(10)), - ?line PrivDir = ?config(priv_dir, Config), - ?line TraceFile = - filename:join(PrivDir, ?MODULE_STRING"_tail_seq.trace"), - ?line AnalysisFile = - filename:join(PrivDir, ?MODULE_STRING"_tail_seq.analysis"), - ?line Start = 1, - ?line Stop = 1000, - ?line Succ = fun (X) -> X + 1 end, - ?line ok = fprof:stop(kill), + PrivDir = proplists:get_value(priv_dir, Config), + TraceFile = filename:join(PrivDir, + ?MODULE_STRING"_tail_seq.trace"), + AnalysisFile = filename:join(PrivDir, + ?MODULE_STRING"_tail_seq.analysis"), + Start = 1, + Stop = 1000, + Succ = fun (X) -> X + 1 end, + ok = fprof:stop(kill), %% - ?line TS0 = erlang:now(), - ?line R = seq_r(Start, Stop, Succ), - ?line TS1 = erlang:now(), + TS0 = erlang:monotonic_time(), + R = seq_r(Start, Stop, Succ), + TS1 = erlang:monotonic_time(), %% - ?line R1 = fprof:apply(fun seq_r/3, [Start, Stop, Succ], - [{file, TraceFile}]), - ?line TS2 = erlang:now(), - ?line ok = fprof:profile([{file,TraceFile}]), - ?line ok = fprof:analyse(), - ?line ok = fprof:analyse(dest, AnalysisFile), - ?line ok = fprof:stop(), - ?line R = R1, + R1 = fprof:apply(fun seq_r/3, [Start, Stop, Succ], + [{file, TraceFile}]), + TS2 = erlang:monotonic_time(), + ok = fprof:profile([{file,TraceFile}]), + ok = fprof:analyse(), + ok = fprof:analyse(dest, AnalysisFile), + ok = fprof:stop(), + R = R1, %% - ?line {ok, [T, P]} = parse(AnalysisFile), - ?line io:format("~p~n~n~p~n", [P, ets:tab2list(T)]), - ?line ok = verify(T, P), - ?line Proc = pid_to_list(self()), - ?line case P of - [{analysis_options, _}, - [{totals, _, Acc, _}], - [{Proc, _, undefined, _} | _]] -> - ok - end, + {ok, [T, P]} = parse(AnalysisFile), + io:format("~p~n~n~p~n", [P, ets:tab2list(T)]), + ok = verify(T, P), + Proc = pid_to_list(self()), + case P of + [{analysis_options, _}, + [{totals, _, Acc, _}], + [{Proc, _, undefined, _} | _]] -> + ok + end, %% - ?line check_own_and_acc(TraceFile,AnalysisFile), + check_own_and_acc(TraceFile,AnalysisFile), %% - ?line ets:delete(T), - ?line file:delete(TraceFile), - ?line file:delete(AnalysisFile), - ?line ?t:timetrap_cancel(Timetrap), - ?line Acc1 = ts_sub(TS1, TS0), - ?line Acc2 = ts_sub(TS2, TS1), - ?line io:format("ts:~w, fprof:~w, bare:~w.~n", [Acc, Acc2, Acc1]), - {comment, io_lib:format("~p times slower", [Acc2/Acc1])}. + ets:delete(T), + file:delete(TraceFile), + file:delete(AnalysisFile), + Acc1 = TS1 - TS0, + Acc2 = TS2 - TS1, + io:format("ts:~w, fprof:~w, bare:~w.~n", [Acc, Acc2, Acc1]), + {comment, io_lib:format("~p times slower", [divide(Acc2,Acc1)])}. %%%--------------------------------------------------------------------- %% Tests the create_file_slow benchmark. create_file_slow(Config) -> case test_server:is_native(lists) orelse - test_server:is_native(file) of - true -> - {skip,"Native libs -- tracing does not work"}; - false -> - do_create_file_slow(Config) + test_server:is_native(file) of + true -> + {skip,"Native libs -- tracing does not work"}; + false -> + do_create_file_slow(Config) end. do_create_file_slow(Config) -> - ?line Timetrap = ?t:timetrap(?t:seconds(40)), - ?line PrivDir = ?config(priv_dir, Config), - ?line TraceFile = - filename:join(PrivDir, ?MODULE_STRING"_create_file_slow.trace"), - ?line AnalysisFile = - filename:join(PrivDir, ?MODULE_STRING"_create_file_slow.analysis"), - ?line DataFile = - filename:join(PrivDir, ?MODULE_STRING"_create_file_slow.data"), - ?line ok = fprof:stop(kill), + PrivDir = proplists:get_value(priv_dir, Config), + TraceFile = filename:join(PrivDir, + ?MODULE_STRING"_create_file_slow.trace"), + AnalysisFile = filename:join(PrivDir, + ?MODULE_STRING"_create_file_slow.analysis"), + DataFile = filename:join(PrivDir, + ?MODULE_STRING"_create_file_slow.data"), + ok = fprof:stop(kill), %% - ?line TS0 = erlang:now(), - ?line ok = create_file_slow(DataFile, 1024), - ?line TS1 = erlang:now(), + TS0 = erlang:monotonic_time(), + ok = create_file_slow(DataFile, 1024), + TS1 = erlang:monotonic_time(), %% - ?line ok = file:delete(DataFile), - ?line TS2 = erlang:now(), - ?line ok = fprof:apply(?MODULE, create_file_slow, [DataFile, 1024], - [{file, TraceFile}]), - ?line TS3 = erlang:now(), - ?line ok = fprof:profile(file, TraceFile), - ?line ok = fprof:analyse(), - ?line ok = fprof:analyse(dest, AnalysisFile), - ?line ok = fprof:stop(), + ok = file:delete(DataFile), + TS2 = erlang:monotonic_time(), + ok = fprof:apply(?MODULE, create_file_slow, [DataFile, 1024], + [{file, TraceFile}]), + TS3 = erlang:monotonic_time(), + ok = fprof:profile(file, TraceFile), + ok = fprof:analyse(), + ok = fprof:analyse(dest, AnalysisFile), + ok = fprof:stop(), %% - ?line {ok, [T, P]} = parse(AnalysisFile), - ?line io:format("~p~n~n~p~n", [P, ets:tab2list(T)]), - ?line ok = verify(T, P), - ?line Proc = pid_to_list(self()), - ?line case P of - [{analysis_options, _}, - [{totals, _, Acc, _}], - [{Proc, _, undefined, _} | _]] -> - ok - end, + {ok, [T, P]} = parse(AnalysisFile), + io:format("~p~n~n~p~n", [P, ets:tab2list(T)]), + ok = verify(T, P), + Proc = pid_to_list(self()), + case P of + [{analysis_options, _}, + [{totals, _, Acc, _}], + [{Proc, _, undefined, _} | _]] -> + ok + end, %% - ?line check_own_and_acc(TraceFile,AnalysisFile), + check_own_and_acc(TraceFile,AnalysisFile), %% - ?line ets:delete(T), - ?line file:delete(DataFile), - ?line file:delete(TraceFile), - ?line file:delete(AnalysisFile), - ?line ?t:timetrap_cancel(Timetrap), - ?line Acc1 = ts_sub(TS1, TS0), - ?line Acc3 = ts_sub(TS3, TS2), - ?line io:format("ts:~w, fprof:~w, bare:~w.~n", [Acc, Acc3, Acc1]), - {comment, io_lib:format("~p times slower", [Acc3/Acc1])}. + ets:delete(T), + file:delete(DataFile), + file:delete(TraceFile), + file:delete(AnalysisFile), + Acc1 = TS1 - TS0, + Acc3 = TS3 - TS2, + io:format("ts:~w, fprof:~w, bare:~w.~n", [Acc, Acc3, Acc1]), + {comment, io_lib:format("~p times slower", [divide(Acc3,Acc1)])}. %%%--------------------------------------------------------------------- -spawn_simple(doc) -> - ["Tests process spawn"]; -spawn_simple(suite) -> - []; +%% Tests process spawn spawn_simple(Config) when is_list(Config) -> - ?line Timetrap = ?t:timetrap(?t:seconds(30)), - ?line PrivDir = ?config(priv_dir, Config), - ?line TraceFile = - filename:join(PrivDir, ?MODULE_STRING"_spawn_simple.trace"), - ?line AnalysisFile = - filename:join(PrivDir, ?MODULE_STRING"_spawn_simple.analysis"), - ?line Start = 1, - ?line Stop = 1000, - ?line Succ = fun (X) -> X + 1 end, - ?line ok = fprof:stop(kill), + PrivDir = proplists:get_value(priv_dir, Config), + TraceFile = filename:join(PrivDir, + ?MODULE_STRING"_spawn_simple.trace"), + AnalysisFile = filename:join(PrivDir, + ?MODULE_STRING"_spawn_simple.analysis"), + Start = 1, + Stop = 1000, + Succ = fun (X) -> X + 1 end, + ok = fprof:stop(kill), %% - ?line TS0 = erlang:now(), - ?line {{_, R1}, {_, R2}} = spawn_simple_test(Start, Stop, Succ), - ?line TS1 = erlang:now(), + TS0 = erlang:monotonic_time(), + {{_, R1}, {_, R2}} = spawn_simple_test(Start, Stop, Succ), + TS1 = erlang:monotonic_time(), %% - ?line ok = fprof:trace(start, TraceFile), - ?line {{P1, R3}, {P2, R4}} = spawn_simple_test(Start, Stop, Succ), - ?line ok = fprof:trace(stop), - ?line TS2 = erlang:now(), - ?line ok = fprof:profile(file, TraceFile), - ?line ok = fprof:analyse(), - ?line ok = fprof:analyse(dest, AnalysisFile), - ?line ok = fprof:stop(), - ?line R1 = R3, - ?line R2 = R4, + ok = fprof:trace(start, TraceFile), + {{P1, R3}, {P2, R4}} = spawn_simple_test(Start, Stop, Succ), + ok = fprof:trace(stop), + TS2 = erlang:monotonic_time(), + ok = fprof:profile(file, TraceFile), + ok = fprof:analyse(), + ok = fprof:analyse(dest, AnalysisFile), + ok = fprof:stop(), + R1 = R3, + R2 = R4, %% - ?line {ok, [T, P]} = parse(AnalysisFile), - ?line io:format("~p~n~n~p~n", [P, ets:tab2list(T)]), - ?line ok = verify(T, P), - ?line Proc1 = pid_to_list(P1), - ?line Proc2 = pid_to_list(P2), - ?line Proc0 = pid_to_list(self()), - ?line io:format("~p~n ~p ~p ~p~n", [P, Proc0, Proc1, Proc2]), - ?line [{analysis_options, _}, [{totals, _, Acc, _}] | Procs] = P, - ?line [[{Proc0, _, undefined, _} | _]] = - lists:filter(fun ([Pt | _]) when element(1, Pt) == Proc0 -> true; - (_) -> false - end, Procs), - ?line [[{Proc1, _, undefined, _}, - {spawned_by, Proc0}, - {spawned_as, {erlang, apply, ["#Fun"++_, []]}}, - {initial_calls, [{erlang, apply, 2}, - {?MODULE, '-spawn_simple_test/3-fun-0-', 4}]} - | _]] = - lists:filter(fun ([Pt | _]) when element(1, Pt) == Proc1 -> true; - (_) -> false - end, Procs), - ?line [[{Proc2, _, undefined, _}, - {spawned_by, Proc0}, - {spawned_as, {erlang, apply, ["#Fun"++_, []]}}, - {initial_calls, [{erlang, apply, 2}, - {?MODULE, '-spawn_simple_test/3-fun-1-', 4}]} - | _]] = - lists:filter(fun ([Pt | _]) when element(1, Pt) == Proc2 -> true; - (_) -> false - end, Procs), - ?line 3 = length(Procs), - ?line R1 = lists:reverse(R2), + {ok, [T, P]} = parse(AnalysisFile), + io:format("~p~n~n~p~n", [P, ets:tab2list(T)]), + ok = verify(T, P), + Proc1 = pid_to_list(P1), + Proc2 = pid_to_list(P2), + Proc0 = pid_to_list(self()), + io:format("~p~n ~p ~p ~p~n", [P, Proc0, Proc1, Proc2]), + [{analysis_options, _}, [{totals, _, Acc, _}] | Procs] = P, + [[{Proc0, _, undefined, _} | _]] = lists:filter( + fun ([Pt | _]) when element(1, Pt) == Proc0 -> true; + (_) -> false + end, Procs), + [[{Proc1, _, undefined, _}, + {spawned_by, Proc0}, + {spawned_as, {erlang, apply, ["#Fun"++_, []]}}, + {initial_calls, [{erlang, apply, 2}, + {?MODULE, '-spawn_simple_test/3-fun-0-', 4}]} + | _]] = lists:filter(fun ([Pt | _]) when element(1, Pt) == Proc1 -> true; + (_) -> false + end, Procs), + [[{Proc2, _, undefined, _}, + {spawned_by, Proc0}, + {spawned_as, {erlang, apply, ["#Fun"++_, []]}}, + {initial_calls, [{erlang, apply, 2}, + {?MODULE, '-spawn_simple_test/3-fun-1-', 4}]} + | _]] = lists:filter(fun ([Pt | _]) when element(1, Pt) == Proc2 -> true; + (_) -> false + end, Procs), + 3 = length(Procs), + R1 = lists:reverse(R2), %% - ?line check_own_and_acc(TraceFile,AnalysisFile), + check_own_and_acc(TraceFile,AnalysisFile), %% - ?line ets:delete(T), - ?line file:delete(TraceFile), - ?line file:delete(AnalysisFile), - ?line ?t:timetrap_cancel(Timetrap), - ?line Acc1 = ts_sub(TS1, TS0), - ?line Acc2 = ts_sub(TS2, TS1), - ?line io:format("ts:~w, fprof:~w, bare:~w.~n", [Acc, Acc2, Acc1]), - {comment, io_lib:format("~p times slower", [Acc2/Acc1])}. + ets:delete(T), + file:delete(TraceFile), + file:delete(AnalysisFile), + Acc1 = TS1 - TS0, + Acc2 = TS2 - TS1, + io:format("ts:~w, fprof:~w, bare:~w.~n", [Acc, Acc2, Acc1]), + {comment, io_lib:format("~p times slower", [divide(Acc2,Acc1)])}. spawn_simple_test(Start, Stop, Succ) -> Parent = self(), - Seq = - spawn_link( - fun () -> - Parent ! {self(), seq(Start, Stop, Succ)} - end), - SeqR = - spawn_link( - fun () -> - Parent ! {self(), seq_r(Start, Stop, Succ)} - end), - receive {Seq, SeqResult} -> - receive {SeqR, SeqRResult} -> - {{Seq, SeqResult}, {SeqR, SeqRResult}} - end + Seq = spawn_link(fun() -> + Parent ! {self(), seq(Start, Stop, Succ)} + end), + + SeqR = spawn_link(fun() -> + Parent ! {self(), seq_r(Start, Stop, Succ)} + end), + receive + {Seq, SeqResult} -> + receive + {SeqR, SeqRResult} -> + {{Seq, SeqResult}, {SeqR, SeqRResult}} + end end. %%%--------------------------------------------------------------------- -imm_tail_seq(doc) -> - ["Tests a tail recursive variant of lists:seq/3 ", - "with immediate trace to profile"]; -imm_tail_seq(suite) -> - []; +%% Tests a tail recursive variant of lists:seq/3 +%% with immediate trace to profile imm_tail_seq(Config) when is_list(Config) -> - ?line Timetrap = ?t:timetrap(?t:seconds(10)), - ?line PrivDir = ?config(priv_dir, Config), - ?line AnalysisFile = - filename:join(PrivDir, ?MODULE_STRING"_imm_tail_seq.analysis"), - ?line Start = 1, - ?line Stop = 1000, - ?line Succ = fun (X) -> X + 1 end, - ?line ok = fprof:stop(kill), - ?line catch eprof:stop(), + PrivDir = proplists:get_value(priv_dir, Config), + AnalysisFile = filename:join(PrivDir, + ?MODULE_STRING"_imm_tail_seq.analysis"), + Start = 1, + Stop = 1000, + Succ = fun (X) -> X + 1 end, + ok = fprof:stop(kill), + catch eprof:stop(), %% - ?line TS0 = erlang:now(), - ?line R0 = seq_r(Start, Stop, Succ), - ?line TS1 = erlang:now(), + TS0 = erlang:monotonic_time(), + R0 = seq_r(Start, Stop, Succ), + TS1 = erlang:monotonic_time(), %% - ?line profiling = eprof:start_profiling([self()]), - ?line TS2 = erlang:now(), - ?line R2 = seq_r(Start, Stop, Succ), - ?line TS3 = erlang:now(), - ?line profiling_stopped = eprof:stop_profiling(), - ?line R2 = R0, + profiling = eprof:start_profiling([self()]), + TS2 = erlang:monotonic_time(), + R2 = seq_r(Start, Stop, Succ), + TS3 = erlang:monotonic_time(), + profiling_stopped = eprof:stop_profiling(), + R2 = R0, %% - ?line eprof:analyze(), - ?line stopped = eprof:stop(), + eprof:analyze(), + stopped = eprof:stop(), %% - ?line {ok, Tracer} = fprof:profile(start), - ?line ok = fprof:trace([start, {tracer, Tracer}]), - ?line TS4 = erlang:now(), - ?line R4 = seq_r(Start, Stop, Succ), - ?line TS5 = erlang:now(), - ?line ok = fprof:trace(stop), - ?line ok = fprof:analyse(), - ?line ok = fprof:analyse(dest, AnalysisFile), - ?line ok = fprof:stop(), - ?line R4 = R0, + {ok, Tracer} = fprof:profile(start), + ok = fprof:trace([start, {tracer, Tracer}]), + TS4 = erlang:monotonic_time(), + R4 = seq_r(Start, Stop, Succ), + TS5 = erlang:monotonic_time(), + ok = fprof:trace(stop), + ok = fprof:analyse(), + ok = fprof:analyse(dest, AnalysisFile), + ok = fprof:stop(), + R4 = R0, %% - ?line {ok, [T, P]} = parse(AnalysisFile), - ?line io:format("~p~n~n~p~n", [P, ets:tab2list(T)]), - ?line ok = verify(T, P), - ?line Proc = pid_to_list(self()), - ?line case P of - [{analysis_options, _}, - [{totals, _, Acc, _}], - [{Proc, _, undefined, _} | _]] -> - ok - end, + {ok, [T, P]} = parse(AnalysisFile), + io:format("~p~n~n~p~n", [P, ets:tab2list(T)]), + ok = verify(T, P), + Proc = pid_to_list(self()), + case P of + [{analysis_options, _}, + [{totals, _, Acc, _}], + [{Proc, _, undefined, _} | _]] -> ok + end, %% - ?line ets:delete(T), - ?line file:delete(AnalysisFile), - ?line ?t:timetrap_cancel(Timetrap), - ?line Acc1 = ts_sub(TS1, TS0), - ?line Acc3 = ts_sub(TS3, TS2), - ?line Acc5 = ts_sub(TS5, TS4), - ?line io:format("~p (plain), ~p (eprof), ~p (fprof), ~p (cpu)~n", - [Acc1/1000, Acc3/1000, Acc5/1000, Acc/1000]), + ets:delete(T), + file:delete(AnalysisFile), + Acc1 = TS1 - TS0, + Acc3 = TS3 - TS2, + Acc5 = TS5 - TS4, + io:format("~p (plain), ~p (eprof), ~p (fprof), ~p (cpu)~n", + [Acc1/1000, Acc3/1000, Acc5/1000, Acc/1000]), {comment, io_lib:format("~p/~p (fprof/eprof) times slower", - [Acc5/Acc1, Acc3/Acc1])}. + [divide(Acc5,Acc1), divide(Acc3,Acc1)])}. %%%--------------------------------------------------------------------- -imm_create_file_slow(doc) -> - ["Tests a tail recursive variant of lists:seq/3 ", - "with immediate trace to profile"]; -imm_create_file_slow(suite) -> - []; +%% Tests a tail recursive variant of lists:seq/3 +%% with immediate trace to profile imm_create_file_slow(Config) when is_list(Config) -> - ?line Timetrap = ?t:timetrap(?t:seconds(60)), - ?line PrivDir = ?config(priv_dir, Config), - ?line DataFile = - filename:join(PrivDir, ?MODULE_STRING"_imm_create_file_slow.data"), - ?line AnalysisFile = - filename:join(PrivDir, ?MODULE_STRING"_imm_create_file_slow.analysis"), - ?line ok = fprof:stop(kill), + PrivDir = proplists:get_value(priv_dir, Config), + DataFile = filename:join(PrivDir, + ?MODULE_STRING"_imm_create_file_slow.data"), + AnalysisFile = filename:join(PrivDir, + ?MODULE_STRING"_imm_create_file_slow.analysis"), + ok = fprof:stop(kill), %% - ?line TS0 = erlang:now(), - ?line ok = create_file_slow(DataFile, 1024), - ?line TS1 = erlang:now(), - ?line ok = file:delete(DataFile), + TS0 = erlang:monotonic_time(), + ok = create_file_slow(DataFile, 1024), + TS1 = erlang:monotonic_time(), + ok = file:delete(DataFile), %% - ?line {ok, Tracer} = fprof:profile(start), - ?line TS2 = erlang:now(), - ?line ok = fprof:apply(?MODULE, create_file_slow, [DataFile, 1024], - [{tracer, Tracer}, continue]), - ?line TS3 = erlang:now(), - ?line ok = fprof:profile(stop), - ?line ok = fprof:analyse(), - ?line ok = fprof:analyse(dest, AnalysisFile), - ?line ok = fprof:stop(), + {ok, Tracer} = fprof:profile(start), + TS2 = erlang:monotonic_time(), + ok = fprof:apply(?MODULE, create_file_slow, [DataFile, 1024], + [{tracer, Tracer}, continue]), + TS3 = erlang:monotonic_time(), + ok = fprof:profile(stop), + ok = fprof:analyse(), + ok = fprof:analyse(dest, AnalysisFile), + ok = fprof:stop(), %% - ?line {ok, [T, P]} = parse(AnalysisFile), - ?line io:format("~p~n~n~p~n", [P, ets:tab2list(T)]), - ?line ok = verify(T, P), - ?line Proc = pid_to_list(self()), - ?line case P of - [{analysis_options, _}, - [{totals, _, Acc, _}], - [{Proc, _, undefined, _} | _]] -> - ok - end, + {ok, [T, P]} = parse(AnalysisFile), + io:format("~p~n~n~p~n", [P, ets:tab2list(T)]), + ok = verify(T, P), + Proc = pid_to_list(self()), + case P of + [{analysis_options, _}, + [{totals, _, Acc, _}], + [{Proc, _, undefined, _} | _]] -> + ok + end, %% - ?line ets:delete(T), - ?line file:delete(DataFile), - ?line file:delete(AnalysisFile), - ?line ?t:timetrap_cancel(Timetrap), - ?line Acc1 = ts_sub(TS1, TS0), - ?line Acc3 = ts_sub(TS3, TS2), - ?line io:format("ts:~w, fprof:~w, bare:~w.~n", [Acc, Acc3, Acc1]), - {comment, io_lib:format("~p times slower", [Acc3/Acc1])}. + ets:delete(T), + file:delete(DataFile), + file:delete(AnalysisFile), + Acc1 = TS1 - TS0, + Acc3 = TS3 - TS2, + io:format("ts:~w, fprof:~w, bare:~w.~n", [Acc, Acc3, Acc1]), + {comment, io_lib:format("~p times slower", [divide(Acc3,Acc1)])}. %%%--------------------------------------------------------------------- -imm_compile(doc) -> - ["Tests to compile a small source file ", - "with immediate trace to profile"]; -imm_compile(suite) -> - []; +%% Tests to compile a small source file with immediate trace to profile imm_compile(Config) when is_list(Config) -> - ?line Timetrap = ?t:timetrap(?t:minutes(20)), - ?line DataDir = ?config(data_dir, Config), - ?line SourceFile = filename:join(DataDir, "foo.erl"), - ?line PrivDir = ?config(priv_dir, Config), - ?line AnalysisFile = - filename:join(PrivDir, ?MODULE_STRING"_imm_compile.analysis"), - ?line ok = fprof:stop(kill), - ?line catch eprof:stop(), + ct:timetrap({minutes, 20}), + DataDir = proplists:get_value(data_dir, Config), + SourceFile = filename:join(DataDir, "foo.erl"), + PrivDir = proplists:get_value(priv_dir, Config), + AnalysisFile = filename:join(PrivDir, + ?MODULE_STRING"_imm_compile.analysis"), + ok = fprof:stop(kill), + catch eprof:stop(), %% - ?line {ok, foo, _} = compile:file(SourceFile, [binary]), - ?line TS0 = erlang:now(), - ?line {ok, foo, _} = compile:file(SourceFile, [binary]), - ?line TS1 = erlang:now(), + {ok, foo, _} = compile:file(SourceFile, [binary]), + TS0 = erlang:monotonic_time(), + {ok, foo, _} = compile:file(SourceFile, [binary]), + TS1 = erlang:monotonic_time(), %% - ?line profiling = eprof:start_profiling([self()]), - ?line TS2 = erlang:now(), - ?line {ok, foo, _} = compile:file(SourceFile, [binary]), - ?line TS3 = erlang:now(), - ?line profiling_stopped = eprof:stop_profiling(), + profiling = eprof:start_profiling([self()]), + TS2 = erlang:monotonic_time(), + {ok, foo, _} = compile:file(SourceFile, [binary]), + TS3 = erlang:monotonic_time(), + profiling_stopped = eprof:stop_profiling(), %% - ?line eprof:analyze(), - ?line stopped = eprof:stop(), + eprof:analyze(), + stopped = eprof:stop(), %% - ?line {ok, Tracer} = fprof:profile(start), - ?line ok = fprof:trace([start, {tracer, Tracer}]), - ?line TS4 = erlang:now(), - ?line {ok, foo, _} = compile:file(SourceFile, [binary]), - ?line TS5 = erlang:now(), - ?line ok = fprof:trace(stop), + {ok, Tracer} = fprof:profile(start), + ok = fprof:trace([start, {tracer, Tracer}]), + TS4 = erlang:monotonic_time(), + {ok, foo, _} = compile:file(SourceFile, [binary]), + TS5 = erlang:monotonic_time(), + ok = fprof:trace(stop), %% - ?line io:format("Analysing...~n"), - ?line ok = fprof:analyse(dest, AnalysisFile), - ?line ok = fprof:stop(), + io:format("Analysing...~n"), + ok = fprof:analyse(dest, AnalysisFile), + ok = fprof:stop(), %% - ?line {ok, [T, P]} = parse(AnalysisFile), - ?line io:format("~p~n", [P]), - ?line Acc1 = ts_sub(TS1, TS0), - ?line Acc3 = ts_sub(TS3, TS2), - ?line Acc5 = ts_sub(TS5, TS4), - ?line io:format("Verifying...~n"), - ?line ok = verify(T, P), - ?line case P of - [{analysis_options, _}, - [{totals, _, Acc, _}] | _] -> - ok - end, + {ok, [T, P]} = parse(AnalysisFile), + io:format("~p~n", [P]), + Acc1 = TS1 - TS0, + Acc3 = TS3 - TS2, + Acc5 = TS5 - TS4, + io:format("Verifying...~n"), + ok = verify(T, P), + case P of + [{analysis_options, _}, + [{totals, _, Acc, _}] | _] -> + ok + end, %% - ?line ets:delete(T), - ?line file:delete(AnalysisFile), - ?line ?t:timetrap_cancel(Timetrap), - ?line io:format("~p (plain), ~p (eprof), ~p (fprof), ~p(cpu)~n", - [Acc1/1000, Acc3/1000, Acc5/1000, Acc/1000]), + ets:delete(T), + file:delete(AnalysisFile), + io:format("~p (plain), ~p (eprof), ~p (fprof), ~p(cpu)~n", + [Acc1/1000, Acc3/1000, Acc5/1000, Acc/1000]), {comment, io_lib:format("~p/~p (fprof/eprof) times slower", - [Acc5/Acc1, Acc3/Acc1])}. + [divide(Acc5,Acc1), divide(Acc3,Acc1)])}. %%%--------------------------------------------------------------------- -cpu_create_file_slow(doc) -> - ["Tests the create_file_slow benchmark using cpu_time"]; -cpu_create_file_slow(suite) -> - []; +%% Tests the create_file_slow benchmark using cpu_time cpu_create_file_slow(Config) when is_list(Config) -> - ?line Timetrap = ?t:timetrap(?t:seconds(40)), - ?line PrivDir = ?config(priv_dir, Config), - ?line TraceFile = - filename:join(PrivDir, ?MODULE_STRING"_cpu_create_file_slow.trace"), - ?line AnalysisFile = - filename:join(PrivDir, ?MODULE_STRING"_cpu_create_file_slow.analysis"), - ?line DataFile = - filename:join(PrivDir, ?MODULE_STRING"_cpu_create_file_slow.data"), - ?line ok = fprof:stop(kill), + PrivDir = proplists:get_value(priv_dir, Config), + TraceFile = + filename:join(PrivDir, ?MODULE_STRING"_cpu_create_file_slow.trace"), + AnalysisFile = + filename:join(PrivDir, ?MODULE_STRING"_cpu_create_file_slow.analysis"), + DataFile = + filename:join(PrivDir, ?MODULE_STRING"_cpu_create_file_slow.data"), + ok = fprof:stop(kill), %% - ?line TS0 = erlang:now(), - ?line Result = (catch fprof:apply(?MODULE, create_file_slow, - [DataFile, 1024], - [{file, TraceFile}, cpu_time])), - ?line TS1 = erlang:now(), - ?line TestResult = - case Result of - ok -> - ?line ok = fprof:profile(file, TraceFile), - ?line ok = fprof:analyse(), - ?line ok = fprof:analyse(dest, AnalysisFile), - ?line ok = fprof:stop(), - %% - ?line {ok, [T, P]} = parse(AnalysisFile), - ?line io:format("~p~n~n~p~n", [P, ets:tab2list(T)]), - ?line ok = verify(T, P), - ?line Proc = pid_to_list(self()), - ?line case P of - [{analysis_options, _}, - [{totals, _, Acc, _}], - [{Proc, _, undefined, _} | _]] -> - ok - end, - %% - ?line check_own_and_acc(TraceFile,AnalysisFile), - %% - ?line ets:delete(T), - ?line file:delete(DataFile), - ?line file:delete(TraceFile), - ?line file:delete(AnalysisFile), - ?line Acc1 = ts_sub(TS1, TS0), - ?line io:format("cpu_ts:~w, fprof:~w~n", [Acc, Acc1]), - {comment, io_lib:format("~p% cpu utilization", - [100*Acc/Acc1])}; - {'EXIT', not_supported} -> - case {os:type(), os:version()} of - {{unix, sunos}, {Major, Minor, _}} - when Major >= 5, Minor >= 7 -> - test_server:fail(Result); - _ -> - {skipped, "not_supported"} - end; - _ -> - test_server:fail(Result) - end, - ?line ?t:timetrap_cancel(Timetrap), + TS0 = erlang:monotonic_time(), + Result = (catch fprof:apply(?MODULE, create_file_slow, + [DataFile, 1024], + [{file, TraceFile}, cpu_time])), + TS1 = erlang:monotonic_time(), + TestResult = + case Result of + ok -> + ok = fprof:profile(file, TraceFile), + ok = fprof:analyse(), + ok = fprof:analyse(dest, AnalysisFile), + ok = fprof:stop(), + %% + {ok, [T, P]} = parse(AnalysisFile), + io:format("~p~n~n~p~n", [P, ets:tab2list(T)]), + ok = verify(T, P), + Proc = pid_to_list(self()), + case P of + [{analysis_options, _}, + [{totals, _, Acc, _}], + [{Proc, _, undefined, _} | _]] -> + ok + end, + %% + check_own_and_acc(TraceFile,AnalysisFile), + %% + ets:delete(T), + file:delete(DataFile), + file:delete(TraceFile), + file:delete(AnalysisFile), + Acc1 = TS1 - TS0, + io:format("cpu_ts:~w, fprof:~w~n", [Acc, Acc1]), + {comment, io_lib:format("~p% cpu utilization", [100*divide(Acc,Acc1)])}; + {'EXIT', not_supported} -> + case {os:type(), os:version()} of + {{unix, sunos}, {Major, Minor, _}} + when Major >= 5, Minor >= 7 -> + ct:fail(Result); + _ -> + {skipped, "not_supported"} + end; + _ -> + ct:fail(Result) + end, TestResult. - %%%--------------------------------------------------------------------- %%% Functions to test %%%--------------------------------------------------------------------- @@ -622,14 +560,14 @@ seq_r(Start, Stop, Succ, R) -> create_file_slow(Name, N) when is_integer(N), N >= 0 -> {ok, FD} = - file:open(Name, [raw, write, delayed_write, binary]), + file:open(Name, [raw, write, delayed_write, binary]), if N > 256 -> - ok = file:write(FD, - lists:map(fun (X) -> <<X:32/unsigned>> end, - lists:seq(0, 255))), - ok = create_file_slow(FD, 256, N); + ok = file:write(FD, + lists:map(fun (X) -> <<X:32/unsigned>> end, + lists:seq(0, 255))), + ok = create_file_slow(FD, 256, N); true -> - ok = create_file_slow(FD, 0, N) + ok = create_file_slow(FD, 0, N) end, ok = file:close(FD). @@ -646,46 +584,44 @@ create_file_slow(FD, M, N) -> %%%--------------------------------------------------------------------- - verify(Tab, [{analysis_options, _}, - [{totals, Cnt, Acc, Own} | _] | Processes]) -> + [{totals, Cnt, Acc, Own} | _] | Processes]) -> Processes_1 = - lists:map( - fun ([{Proc, Cnt_P, undefined, Own_P} | _]) -> - case sum_process(Tab, Proc) of - {Proc, Cnt_P, Acc_P, Own_P} = Clocks - when Acc_P >= Own_P -> - Clocks; - Weird -> - throw({error, [?MODULE, ?LINE, Weird]}) - end - end, - Processes), + lists:map( + fun ([{Proc, Cnt_P, undefined, Own_P} | _]) -> + case sum_process(Tab, Proc) of + {Proc, Cnt_P, Acc_P, Own_P} = Clocks + when Acc_P >= Own_P -> + Clocks; + Weird -> + throw({error, [?MODULE, ?LINE, Weird]}) + end + end, + Processes), case lists:foldl( - fun ({_, Cnt_P2, Acc_P2, Own_P2}, - {totals, Cnt_T, Acc_T, Own_T}) -> - {totals, Cnt_P2+Cnt_T, Acc_P2+Acc_T, Own_P2+Own_T} - end, - {totals, 0, 0, 0}, - Processes_1) of - {totals, Cnt, Acc_T, Own} when Acc_T >= Acc -> - ok; - Weird -> - throw({error, [?MODULE, ?LINE, Weird]}) + fun ({_, Cnt_P2, Acc_P2, Own_P2}, + {totals, Cnt_T, Acc_T, Own_T}) -> + {totals, Cnt_P2+Cnt_T, Acc_P2+Acc_T, Own_P2+Own_T} + end, + {totals, 0, 0, 0}, + Processes_1) of + {totals, Cnt, Acc_T, Own} when Acc_T >= Acc -> + ok; + Weird -> + throw({error, [?MODULE, ?LINE, Weird]}) end. - sum_process(Tab, Proc) -> ets_select_fold( Tab, [{{{Proc, '_'}, '_'}, [], ['$_']}], 100, fun ({{P, MFA}, {Callers, {MFA, Cnt, Acc, Own}, Called}}, - {P, Cnt_P, Acc_P, Own_P}) when P == Proc -> - ok = verify_callers(Tab, Proc, MFA, Callers), - ok = verify_called(Tab, Proc, MFA, Called), - {P, Cnt+Cnt_P, Acc+Acc_P, Own+Own_P}; - (Weird, Clocks) -> - throw({error, [?MODULE, ?LINE, Weird, Clocks]}) + {P, Cnt_P, Acc_P, Own_P}) when P == Proc -> + ok = verify_callers(Tab, Proc, MFA, Callers), + ok = verify_called(Tab, Proc, MFA, Called), + {P, Cnt+Cnt_P, Acc+Acc_P, Own+Own_P}; + (Weird, Clocks) -> + throw({error, [?MODULE, ?LINE, Weird, Clocks]}) end, {Proc, 0, 0, 0}). @@ -694,31 +630,31 @@ verify_callers(_, _, _, []) -> verify_callers(Tab, Proc, MFA, [{Caller, Cnt, Acc, Own} | Tail]) -> Id = {Proc, Caller}, case ets:lookup(Tab, Id) of - [{Id, {_, {Caller, _, _, _}, Called}}] -> - case lists:keysearch(MFA, 1, Called) of - {value, {MFA, Cnt, Acc, Own}} -> - verify_callers(Tab, Proc, MFA, Tail); - false -> - throw({error, [?MODULE, ?LINE, MFA, Id]}) - end; - Weird -> - throw({error, [?MODULE, ?LINE, Weird]}) + [{Id, {_, {Caller, _, _, _}, Called}}] -> + case lists:keysearch(MFA, 1, Called) of + {value, {MFA, Cnt, Acc, Own}} -> + verify_callers(Tab, Proc, MFA, Tail); + false -> + throw({error, [?MODULE, ?LINE, MFA, Id]}) + end; + Weird -> + throw({error, [?MODULE, ?LINE, Weird]}) end. - + verify_called(_, _, _, []) -> ok; verify_called(Tab, Proc, MFA, [{Called, Cnt, Acc, Own} | Tail]) -> Id = {Proc, Called}, case ets:lookup(Tab, Id) of - [{Id, {Callers, {Called, _, _, _}, _}}] -> - case lists:keysearch(MFA, 1, Callers) of - {value, {MFA, Cnt, Acc, Own}} -> - verify_called(Tab, Proc, MFA, Tail); - false -> - throw({error, [?MODULE, ?LINE, MFA, Id]}) - end; - Weird -> - throw({error, [?MODULE, ?LINE, Weird]}) + [{Id, {Callers, {Called, _, _, _}, _}}] -> + case lists:keysearch(MFA, 1, Callers) of + {value, {MFA, Cnt, Acc, Own}} -> + verify_called(Tab, Proc, MFA, Tail); + false -> + throw({error, [?MODULE, ?LINE, MFA, Id]}) + end; + Weird -> + throw({error, [?MODULE, ?LINE, Weird]}) end. @@ -728,12 +664,12 @@ verify_called(Tab, Proc, MFA, [{Called, Cnt, Acc, Own} | Tail]) -> %% entries when they are read. parse(Filename) -> case file:open(Filename, [read]) of - {ok, FD} -> - Result = parse_stream(FD), - file:close(FD), - Result; - Error -> - Error + {ok, FD} -> + Result = parse_stream(FD), + file:close(FD), + Result; + Error -> + Error end. parse_stream(FD) -> @@ -742,31 +678,31 @@ parse_stream(FD) -> parse_stream(FD, Tab, R, Proc) -> case catch io:read(FD, '') of - {'EXIT', _} -> - {error, [?MODULE, ?LINE]}; - {ok, Term} -> - case parse_term(Term) of - {ok, {analysis_options, _} = Term_1} - when Proc == void -> - parse_stream(FD, Tab, [Term_1 | R], analysis_options); - {ok, [{totals, _, _, _} | _] = Term_1} - when Proc == analysis_options -> - parse_stream(FD, Tab, [Term_1 | R], totals); - {ok, [{P, _, _, _} | _] = Term_1} -> - parse_stream(FD, Tab, [Term_1 | R], P); - {ok, {_Callers, {MFA, _, _, _}, _Called} = Term_1} - when Proc == totals; is_list(Proc) -> - ets:insert(Tab, {{Proc, MFA}, Term_1}), - parse_stream(FD, Tab, R, Proc); - {ok, Term_1} -> - {error, [?MODULE, ?LINE, Term_1]}; - E -> - E - end; - eof -> - {ok, [Tab, lists:reverse(R)]}; - Error -> - Error + {'EXIT', _} -> + {error, [?MODULE, ?LINE]}; + {ok, Term} -> + case parse_term(Term) of + {ok, {analysis_options, _} = Term_1} + when Proc == void -> + parse_stream(FD, Tab, [Term_1 | R], analysis_options); + {ok, [{totals, _, _, _} | _] = Term_1} + when Proc == analysis_options -> + parse_stream(FD, Tab, [Term_1 | R], totals); + {ok, [{P, _, _, _} | _] = Term_1} -> + parse_stream(FD, Tab, [Term_1 | R], P); + {ok, {_Callers, {MFA, _, _, _}, _Called} = Term_1} + when Proc == totals; is_list(Proc) -> + ets:insert(Tab, {{Proc, MFA}, Term_1}), + parse_stream(FD, Tab, R, Proc); + {ok, Term_1} -> + {error, [?MODULE, ?LINE, Term_1]}; + E -> + E + end; + eof -> + {ok, [Tab, lists:reverse(R)]}; + Error -> + Error end. parse_term({Callers, Func, Called}) @@ -776,10 +712,10 @@ parse_term({Callers, Func, Called}) Called_1 = lists:map(fun parse_clocks/1, Called), Result = {Callers_1, Func_1, Called_1}, case chk_invariant(Result) of - ok -> - {ok, Result}; - Error -> - Error + ok -> + {ok, Result}; + Error -> + Error end; parse_term([{_, _, _, _} = Clocks | Tail]) -> {ok, [parse_clocks(Clocks) | Tail]}; @@ -797,41 +733,41 @@ parse_clocks(Clocks) -> chk_invariant({Callers, {MFA, Cnt, Acc, Own}, Called} = Term) -> {_, Callers_Cnt, Callers_Acc, Callers_Own} = Callers_Sum = sum(Callers), -% {_, Called_Cnt, Called_Acc, Called_Own} = Called_Sum = sum(Called), + % {_, Called_Cnt, Called_Acc, Called_Own} = Called_Sum = sum(Called), case {MFA, - lists:keymember(suspend, 1, Callers), - lists:keymember(garbage_collect, 1, Callers), - Called} of - {suspend, false, _, []} -> - ok; - {suspend, _, _, _} = Weird -> - {error, [?MODULE, ?LINE, Weird, Term]}; - {garbage_collect, false, false, []} -> - ok; - {garbage_collect, false, false, [{suspend, _, _, _}]} -> - ok; - {garbage_collect, _, _, _} = Weird -> - {error, [?MODULE, ?LINE, Weird, Term]}; - {undefined, false, false, _} - when Callers == [], Cnt == 0, Acc == 0, Own == 0 -> - ok; - {undefined, _, _, _} = Weird -> - {error, [?MODULE, ?LINE, Weird, Term]}; - {_, _, _, _} -> - case chk_self_call(Term) of - true when Callers_Cnt /= Cnt; Callers_Acc /= Acc; - Callers_Own /= Own -> - {error, [?MODULE, ?LINE, Callers_Sum, Term]}; -% true when Called_Acc + Own /= Acc -> -% io:format("WARNING: ~p:~p, ~p, ~p.~n", -% [?MODULE, ?LINE, Term, Called_Sum]), -% {error, [?MODULE, ?LINE, Term, Called_Sum]}; -% ok; - true -> - ok; - false -> - {error, [?MODULE, ?LINE, Term]} - end + lists:keymember(suspend, 1, Callers), + lists:keymember(garbage_collect, 1, Callers), + Called} of + {suspend, false, _, []} -> + ok; + {suspend, _, _, _} = Weird -> + {error, [?MODULE, ?LINE, Weird, Term]}; + {garbage_collect, false, false, []} -> + ok; + {garbage_collect, false, false, [{suspend, _, _, _}]} -> + ok; + {garbage_collect, _, _, _} = Weird -> + {error, [?MODULE, ?LINE, Weird, Term]}; + {undefined, false, false, _} + when Callers == [], Cnt == 0, Acc == 0, Own == 0 -> + ok; + {undefined, _, _, _} = Weird -> + {error, [?MODULE, ?LINE, Weird, Term]}; + {_, _, _, _} -> + case chk_self_call(Term) of + true when Callers_Cnt /= Cnt; Callers_Acc /= Acc; + Callers_Own /= Own -> + {error, [?MODULE, ?LINE, Callers_Sum, Term]}; + % true when Called_Acc + Own /= Acc -> + % io:format("WARNING: ~p:~p, ~p, ~p.~n", + % [?MODULE, ?LINE, Term, Called_Sum]), + % {error, [?MODULE, ?LINE, Term, Called_Sum]}; + % ok; + true -> + ok; + false -> + {error, [?MODULE, ?LINE, Term]} + end end. ts_sub({A, B, C}, {A0, B0, C0}) -> @@ -839,28 +775,28 @@ ts_sub({A, B, C}, {A0, B0, C0}) -> sum(Funcs) -> {sum, _Cnt, _Acc, _Own} = - lists:foldl( - fun ({_, C1, A1, O1}, {sum, C2, A2, O2}) -> - {sum, C1+C2, A1+A2, O1+O2} - end, - {sum, 0, 0, 0}, - Funcs). + lists:foldl( + fun ({_, C1, A1, O1}, {sum, C2, A2, O2}) -> + {sum, C1+C2, A1+A2, O1+O2} + end, + {sum, 0, 0, 0}, + Funcs). chk_self_call({Callers, {MFA, _Cnt, _Acc, _Own}, Called}) -> case lists:keysearch(MFA, 1, Callers) of - false -> - true; - {value, {MFA, C, 0, O}} -> - case lists:keysearch(MFA, 1, Called) of - false -> - false; - {value, {MFA, C, 0, O}} -> - true; - {value, _} -> - false - end; - {value, _} -> - false + false -> + true; + {value, {MFA, C, 0, O}} -> + case lists:keysearch(MFA, 1, Called) of + false -> + false; + {value, {MFA, C, 0, O}} -> + true; + {value, _} -> + false + end; + {value, _} -> + false end. @@ -878,9 +814,8 @@ ets_select_fold_1('$end_of_table', _, Acc) -> Acc; ets_select_fold_1({Matches, Continuation}, Fun, Acc) -> ets_select_fold_1(ets:select(Continuation), - Fun, - lists:foldl(Fun, Acc, Matches)). - + Fun, + lists:foldl(Fun, Acc, Matches)). % ets_select_foreach(Table, MatchSpec, Limit, Fun) -> @@ -909,7 +844,7 @@ check_own_and_acc(TraceFile, AnalysisFile) -> check_own_and_acc(TraceFile, AnalysisFile, HandlerFun) -> dbg:trace_client(file,TraceFile,{HandlerFun,{init,self()}}), receive {result,Result} -> - compare(Result,get_own_and_acc_from_analysis(AnalysisFile)) + compare(Result,get_own_and_acc_from_analysis(AnalysisFile)) end. %% handle_trace_traced(Trace, Msg) -> @@ -923,21 +858,21 @@ handle_trace(Trace,{init,Parent}) -> handle_trace({trace_ts,Pid,in,MFA,TS},P) -> ?dbg("~p",[{{in,Pid,MFA},get(Pid)}]), case get(Pid) of - [suspend|[suspend|_]=NewStack] -> - T = ts_sub(TS,get({Pid,last_ts})), - update_acc(Pid,NewStack,T), - put(Pid,NewStack); - [suspend|NewStack] = Stack -> - T = ts_sub(TS,get({Pid,last_ts})), - update_acc(Pid,Stack,T), - put(Pid,NewStack); - [] -> - put(Pid,[MFA]), - insert(Pid,MFA); - undefined -> - put(first_ts,TS), - put(Pid,[MFA]), - insert(Pid,MFA) + [suspend|[suspend|_]=NewStack] -> + T = ts_sub(TS,get({Pid,last_ts})), + update_acc(Pid,NewStack,T), + put(Pid,NewStack); + [suspend|NewStack] = Stack -> + T = ts_sub(TS,get({Pid,last_ts})), + update_acc(Pid,Stack,T), + put(Pid,NewStack); + [] -> + put(Pid,[MFA]), + insert(Pid,MFA); + undefined -> + put(first_ts,TS), + put(Pid,[MFA]), + insert(Pid,MFA) end, put({Pid,last_ts},TS), P; @@ -945,17 +880,17 @@ handle_trace({trace_ts,Pid,out,_MfaOrZero,TS},P) -> ?dbg("~p",[{{out,Pid,_MfaOrZero},get(Pid)}]), T = ts_sub(TS,get({Pid,last_ts})), case get(Pid) of - [suspend|S] = Stack -> - update_acc(Pid,S,T), - put(Pid,[suspend|Stack]); - [MFA|_] = Stack -> - insert(Pid,suspend), - update_own(Pid,MFA,T), - update_acc(Pid,Stack,T), - put(Pid,[suspend|Stack]); - [] -> - insert(Pid,suspend), - put(Pid,[suspend]) + [suspend|S] = Stack -> + update_acc(Pid,S,T), + put(Pid,[suspend|Stack]); + [MFA|_] = Stack -> + insert(Pid,suspend), + update_own(Pid,MFA,T), + update_acc(Pid,Stack,T), + put(Pid,[suspend|Stack]); + [] -> + insert(Pid,suspend), + put(Pid,[suspend]) end, put({Pid,last_ts},TS), P; @@ -963,26 +898,26 @@ handle_trace({trace_ts,Pid,call,MFA,{cp,Caller},TS},P) -> ?dbg("~p",[{{call,Pid,MFA},get(Pid)}]), T = ts_sub(TS,get({Pid,last_ts})), case get(Pid) of - [MFA|_] = Stack -> - %% recursive - update_own(Pid,MFA,T), - update_acc(Pid,Stack,T); - [CallingMFA|_] = Stack when Caller==undefined -> - insert(Pid,MFA), - update_own(Pid,CallingMFA,T), - update_acc(Pid,Stack,T), - put(Pid,[MFA|Stack]); - [] when Caller==undefined -> - insert(Pid,MFA), - insert(Pid,MFA), - put(Pid,[MFA]); - Stack0 -> - Stack = [CallingMFA|_] = insert_caller(Caller,Stack0,[]), - insert(Pid,MFA), - insert(Pid,Caller), - update_own(Pid,CallingMFA,T), - update_acc(Pid,Stack,T), - put(Pid,[MFA|Stack]) + [MFA|_] = Stack -> + %% recursive + update_own(Pid,MFA,T), + update_acc(Pid,Stack,T); + [CallingMFA|_] = Stack when Caller==undefined -> + insert(Pid,MFA), + update_own(Pid,CallingMFA,T), + update_acc(Pid,Stack,T), + put(Pid,[MFA|Stack]); + [] when Caller==undefined -> + insert(Pid,MFA), + insert(Pid,MFA), + put(Pid,[MFA]); + Stack0 -> + Stack = [CallingMFA|_] = insert_caller(Caller,Stack0,[]), + insert(Pid,MFA), + insert(Pid,Caller), + update_own(Pid,CallingMFA,T), + update_acc(Pid,Stack,T), + put(Pid,[MFA|Stack]) end, put({Pid,last_ts},TS), P; @@ -990,59 +925,91 @@ handle_trace({trace_ts,Pid,return_to,MFA,TS},P) -> ?dbg("~p",[{{return_to,Pid,MFA},get(Pid)}]), T = ts_sub(TS,get({Pid,last_ts})), case get(Pid) of - [MFA|_] = Stack -> - %% recursive - update_own(Pid,MFA,T), - update_acc(Pid,Stack,T), - put(Pid,Stack); - [ReturnFromMFA,MFA|RestOfStack] = Stack -> - update_own(Pid,ReturnFromMFA,T), - update_acc(Pid,Stack,T), - put(Pid,[MFA|RestOfStack]); - [ReturnFromMFA|RestOfStack] = Stack -> - update_own(Pid,ReturnFromMFA,T), - update_acc(Pid,Stack,T), - case find_return_to(MFA,RestOfStack) of - [] when MFA==undefined -> - put(Pid,[]); - [] -> - insert(Pid,MFA), - put(Pid,[MFA]); - NewStack -> - put(Pid,NewStack) - end + [MFA|_] = Stack -> + %% recursive + update_own(Pid,MFA,T), + update_acc(Pid,Stack,T), + put(Pid,Stack); + [ReturnFromMFA,MFA|RestOfStack] = Stack -> + update_own(Pid,ReturnFromMFA,T), + update_acc(Pid,Stack,T), + put(Pid,[MFA|RestOfStack]); + [ReturnFromMFA|RestOfStack] = Stack -> + update_own(Pid,ReturnFromMFA,T), + update_acc(Pid,Stack,T), + case find_return_to(MFA,RestOfStack) of + [] when MFA==undefined -> + put(Pid,[]); + [] -> + insert(Pid,MFA), + put(Pid,[MFA]); + NewStack -> + put(Pid,NewStack) + end end, put({Pid,last_ts},TS), P; -handle_trace({trace_ts,Pid,gc_start,_,TS},P) -> - ?dbg("~p",[{{gc_start,Pid},get(Pid)}]), +handle_trace({trace_ts,Pid,gc_minor_start,_,TS},P) -> + ?dbg("~p",[{{gc_minor_start,Pid},get(Pid)}]), case get(Pid) of - [suspend|_] = Stack -> - T = ts_sub(TS,get({Pid,last_ts})), - insert(Pid,garbage_collect), - update_acc(Pid,Stack,T), - put(Pid,[garbage_collect|Stack]); - [CallingMFA|_] = Stack -> - T = ts_sub(TS,get({Pid,last_ts})), - insert(Pid,garbage_collect), - update_own(Pid,CallingMFA,T), - update_acc(Pid,Stack,T), - put(Pid,[garbage_collect|Stack]); - undefined -> - put(first_ts,TS), - put(Pid,[garbage_collect]), - insert(Pid,garbage_collect) + [suspend|_] = Stack -> + T = ts_sub(TS,get({Pid,last_ts})), + insert(Pid,garbage_collect), + update_acc(Pid,Stack,T), + put(Pid,[garbage_collect|Stack]); + [CallingMFA|_] = Stack -> + T = ts_sub(TS,get({Pid,last_ts})), + insert(Pid,garbage_collect), + update_own(Pid,CallingMFA,T), + update_acc(Pid,Stack,T), + put(Pid,[garbage_collect|Stack]); + undefined -> + put(first_ts,TS), + put(Pid,[garbage_collect]), + insert(Pid,garbage_collect) end, put({Pid,last_ts},TS), P; -handle_trace({trace_ts,Pid,gc_end,_,TS},P) -> - ?dbg("~p",[{{gc_end,Pid},get(Pid)}]), +handle_trace({trace_ts,Pid,gc_major_start,_,TS},P) -> + ?dbg("~p",[{{gc_minor_start,Pid},get(Pid)}]), + case get(Pid) of + [suspend|_] = Stack -> + T = ts_sub(TS,get({Pid,last_ts})), + insert(Pid,garbage_collect), + update_acc(Pid,Stack,T), + put(Pid,[garbage_collect|Stack]); + [CallingMFA|_] = Stack -> + T = ts_sub(TS,get({Pid,last_ts})), + insert(Pid,garbage_collect), + update_own(Pid,CallingMFA,T), + update_acc(Pid,Stack,T), + put(Pid,[garbage_collect|Stack]); + undefined -> + put(first_ts,TS), + put(Pid,[garbage_collect]), + insert(Pid,garbage_collect) + end, + put({Pid,last_ts},TS), + P; +handle_trace({trace_ts,Pid,gc_minor_end,_,TS},P) -> + ?dbg("~p",[{{gc_minor_end,Pid},get(Pid)}]), T = ts_sub(TS,get({Pid,last_ts})), case get(Pid) of - [garbage_collect|RestOfStack] = Stack -> - update_own(Pid,garbage_collect,T), - update_acc(Pid,Stack,T), - put(Pid,RestOfStack) + [garbage_collect|RestOfStack] = Stack -> + update_own(Pid,garbage_collect,T), + update_acc(Pid,Stack,T), + put(Pid,RestOfStack) + end, + put({Pid,last_ts},TS), + P; +handle_trace({trace_ts,Pid,gc_major_end,_,TS},P) -> + ?dbg("~p",[{{gc_major_end,Pid},get(Pid)}]), + T = ts_sub(TS,get({Pid,last_ts})), + case get(Pid) of + [garbage_collect|RestOfStack] = Stack -> + update_own(Pid,garbage_collect,T), + update_acc(Pid,Stack,T), + put(Pid,RestOfStack) end, put({Pid,last_ts},TS), P; @@ -1050,27 +1017,45 @@ handle_trace({trace_ts,Pid,spawn,NewPid,{M,F,Args},TS},P) -> MFA = {M,F,length(Args)}, ?dbg("~p",[{{spawn,Pid,NewPid,MFA},get(Pid)}]), T = ts_sub(TS,get({Pid,last_ts})), - put({NewPid,last_ts},TS), - put(NewPid,[suspend,MFA]), - insert(NewPid,suspend), - insert(NewPid,MFA), + case get(NewPid) of + undefined -> + put({NewPid,last_ts},TS), + put(NewPid,[suspend,MFA]), + insert(NewPid,suspend), + insert(NewPid,MFA); + _Else -> + ok + end, case get(Pid) of - [SpawningMFA|_] = Stack -> - update_own(Pid,SpawningMFA,T), - update_acc(Pid,Stack,T) + [SpawningMFA|_] = Stack -> + update_own(Pid,SpawningMFA,T), + update_acc(Pid,Stack,T) end, put({Pid,last_ts},TS), P; +handle_trace({trace_ts,NewPid,spawned,Pid,{M,F,Args},TS},P) -> + MFA = {M,F,length(Args)}, + ?dbg("~p",[{{spawned,NewPid,Pid,MFA},get(NewPid)}]), + case get(NewPid) of + undefined -> + put({NewPid,last_ts},TS), + put(NewPid,[suspend,MFA]), + insert(NewPid,suspend), + insert(NewPid,MFA); + _Else -> + ok + end, + P; handle_trace({trace_ts,Pid,exit,_Reason,TS},P) -> ?dbg("~p",[{{exit,Pid,_Reason},get(Pid)}]), T = ts_sub(TS,get({Pid,last_ts})), case get(Pid) of - [DyingMFA|_] = Stack -> - update_own(Pid,DyingMFA,T), - update_acc(Pid,Stack,T), - put(Pid,[]); - [] -> - ok + [DyingMFA|_] = Stack -> + update_own(Pid,DyingMFA,T), + update_acc(Pid,Stack,T), + put(Pid,[]); + [] -> + ok end, put({Pid,last_ts},TS), P; @@ -1088,6 +1073,7 @@ handle_trace(end_of_trace,P) -> P ! {result,[{totals,TotAcc,TotOwn}|ProcOwns]++Result}, P; handle_trace(Other,_P) -> + ct:log("Got unexpected trace message: ~p",[Other]), exit({unexpected,Other}). find_return_to(MFA,[MFA|_]=Stack) -> @@ -1106,10 +1092,10 @@ insert_caller(MFA,[],Result) -> insert(Pid,MFA) -> case ets:member(fprof_verify_tab,{Pid,MFA}) of - false -> - ets:insert(fprof_verify_tab,{{Pid,MFA},0,0}); - true -> - ok + false -> + ets:insert(fprof_verify_tab,{{Pid,MFA},0,0}); + true -> + ok end. update_own(Pid,MFA,T) -> @@ -1117,11 +1103,11 @@ update_own(Pid,MFA,T) -> update_acc(Pid,[MFA|Rest],T) -> case lists:member(MFA,Rest) of - true -> - %% Only charge one time for recursive functions - ok; - false -> - ets:update_counter(fprof_verify_tab,{Pid,MFA},{2,T}) + true -> + %% Only charge one time for recursive functions + ok; + false -> + ets:update_counter(fprof_verify_tab,{Pid,MFA},{2,T}) end, update_acc(Pid,Rest,T); update_acc(_Pid,[],_T) -> @@ -1139,63 +1125,63 @@ get_last_ts([],Last) -> get_proc_owns([{{Pid,_MFA},_Acc,Own}|Rest],Result,Sum) -> NewResult = - case lists:keysearch(Pid,1,Result) of - {value,{Pid,undefined,PidOwn}} -> - lists:keyreplace(Pid,1,Result,{Pid,undefined,PidOwn+Own}); - false -> - [{Pid,undefined,Own}|Result] + case lists:keysearch(Pid,1,Result) of + {value,{Pid,undefined,PidOwn}} -> + lists:keyreplace(Pid,1,Result,{Pid,undefined,PidOwn+Own}); + false -> + [{Pid,undefined,Own}|Result] end, get_proc_owns(Rest,NewResult,Sum+Own); get_proc_owns([],Result,Sum) -> {Sum,Result}. - + compare([X|Rest],FprofResult) -> FprofResult1 = - case lists:member(X,FprofResult) of - true -> - ?dbg("~p",[X]), - lists:delete(X,FprofResult); - false -> - case lists:keysearch(element(1,X),1,FprofResult) of - {value,Fprof} -> - put(compare_error,true), - io:format("Error: Different values\n" - "Fprof: ~p\n" - "Simulator: ~p",[Fprof,X]), - lists:delete(Fprof,FprofResult); - false -> - put(compare_error,true), - io:format("Error: Missing in fprof: ~p",[X]), - FprofResult - end - end, + case lists:member(X,FprofResult) of + true -> + ?dbg("~p",[X]), + lists:delete(X,FprofResult); + false -> + case lists:keysearch(element(1,X),1,FprofResult) of + {value,Fprof} -> + put(compare_error,true), + io:format("Error: Different values\n" + "Fprof: ~p\n" + "Simulator: ~p",[Fprof,X]), + lists:delete(Fprof,FprofResult); + false -> + put(compare_error,true), + io:format("Error: Missing in fprof: ~p",[X]), + FprofResult + end + end, compare(Rest,FprofResult1); compare([],Rest) -> case {remove_undefined(Rest,[]),get(compare_error)} of - {[],undefined} -> ok; - {Error,_} -> - case Error of - [] -> ok; - _ -> io:format("\nMissing in simulator results:\n~p\n",[Error]) - end, - ?t:fail({error,mismatch_between_simulator_and_fprof}) + {[],undefined} -> ok; + {Error,_} -> + case Error of + [] -> ok; + _ -> io:format("\nMissing in simulator results:\n~p\n",[Error]) + end, + ct:fail({error,mismatch_between_simulator_and_fprof}) end. - + remove_undefined([{{_Pid,undefined},_,_}|Rest],Result) -> remove_undefined(Rest,Result); remove_undefined([X|Rest],Result) -> remove_undefined(Rest,[X|Result]); remove_undefined([],Result) -> Result. - + get_own_and_acc_from_analysis(Log) -> case file:consult(Log) of - {ok,[_Options,[{totals,_,TotAcc,TotOwn}]|Rest]} -> - get_own_and_acc(undefined,Rest, - [{totals,m1000(TotAcc),m1000(TotOwn)}]); - Error -> - exit({error,{cant_open,Log,Error}}) + {ok,[_Options,[{totals,_,TotAcc,TotOwn}]|Rest]} -> + get_own_and_acc(undefined,Rest, + [{totals,m1000(TotAcc),m1000(TotOwn)}]); + Error -> + exit({error,{cant_open,Log,Error}}) end. get_own_and_acc(_,[[{PidStr,_,Acc,Own}|_]|Rest],Result) -> @@ -1211,3 +1197,5 @@ m1000(undefined) -> m1000(X) -> round(X*1000). +divide(_,0) -> inf; +divide(A,B) -> A / B. diff --git a/lib/tools/test/fprof_SUITE_data/foo.erl b/lib/tools/test/fprof_SUITE_data/foo.erl index eaa8132b1e..6944425980 100644 --- a/lib/tools/test/fprof_SUITE_data/foo.erl +++ b/lib/tools/test/fprof_SUITE_data/foo.erl @@ -1,13 +1,14 @@ -%% ``The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved via the world wide web at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% ``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. %% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB. %% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings diff --git a/lib/tools/test/ignore_cores.erl b/lib/tools/test/ignore_cores.erl index 8b1ac0fe6c..25dce346b9 100644 --- a/lib/tools/test/ignore_cores.erl +++ b/lib/tools/test/ignore_cores.erl @@ -1,18 +1,19 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% 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 %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% @@ -27,7 +28,7 @@ -module(ignore_cores). --include_lib("test_server/include/test_server.hrl"). +-include_lib("common_test/include/ct.hrl"). -export([init/1, fini/1, setup/3, setup/4, restore/1, dir/1]). @@ -52,7 +53,7 @@ init(Config) -> fini(Config) -> #ignore_cores{org_cwd = OrgCWD, org_path = OrgPath, - org_pwd_env = OrgPWD} = ?config(ignore_cores, Config), + org_pwd_env = OrgPWD} = proplists:get_value(ignore_cores, Config), ok = file:set_cwd(OrgCWD), true = code:set_path(OrgPath), case OrgPWD of @@ -69,10 +70,10 @@ setup(Suite, Testcase, Config, SetCwd) when is_atom(Suite), is_list(Config) -> #ignore_cores{org_cwd = OrgCWD, org_path = OrgPath, - org_pwd_env = OrgPWD} = ?config(ignore_cores, Config), + org_pwd_env = OrgPWD} = proplists:get_value(ignore_cores, Config), Path = lists:map(fun (".") -> OrgCWD; (Dir) -> Dir end, OrgPath), true = code:set_path(Path), - PrivDir = ?config(priv_dir, Config), + PrivDir = proplists:get_value(priv_dir, Config), IgnDir = filename:join([PrivDir, atom_to_list(Suite) ++ "_" @@ -93,7 +94,7 @@ setup(Suite, Testcase, Config, SetCwd) when is_atom(Suite), end, ok = file:write_file(filename:join([IgnDir, "ignore_core_files"]), <<>>), %% cores are dumped in /cores on MacOS X - CoresDir = case {?t:os_type(), filelib:is_dir("/cores")} of + CoresDir = case {os:type(), filelib:is_dir("/cores")} of {{unix,darwin}, true} -> filelib:fold_files("/cores", "^core.*$", @@ -118,7 +119,7 @@ restore(Config) -> org_path = OrgPath, org_pwd_env = OrgPWD, ign_dir = IgnDir, - cores_dir = CoresDir} = ?config(ignore_cores, Config), + cores_dir = CoresDir} = proplists:get_value(ignore_cores, Config), try case CoresDir of false -> @@ -154,5 +155,5 @@ restore(Config) -> dir(Config) -> - #ignore_cores{ign_dir = Dir} = ?config(ignore_cores, Config), + #ignore_cores{ign_dir = Dir} = proplists:get_value(ignore_cores, Config), Dir. diff --git a/lib/tools/test/instrument_SUITE.erl b/lib/tools/test/instrument_SUITE.erl index bc886d47c3..f37d28c277 100644 --- a/lib/tools/test/instrument_SUITE.erl +++ b/lib/tools/test/instrument_SUITE.erl @@ -1,150 +1,117 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2011. All Rights Reserved. +%% Copyright Ericsson AB 1998-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% 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 %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% -module(instrument_SUITE). --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2, - init_per_testcase/2,end_per_testcase/2]). - +-export([all/0, suite/0]). -export(['+Mim true'/1, '+Mis true'/1]). --include_lib("test_server/include/test_server.hrl"). +-include_lib("common_test/include/ct.hrl"). -init_per_testcase(_Case, Config) -> - ?line Dog=?t:timetrap(10000), - [{watchdog, Dog}|Config]. - -end_per_testcase(_Case, Config) -> - Dog=?config(watchdog, Config), - ?t:timetrap_cancel(Dog), - ok. - -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap,{seconds,10}}]. all() -> ['+Mim true', '+Mis true']. -groups() -> - []. - -init_per_suite(Config) -> - Config. -end_per_suite(_Config) -> - ok. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -'+Mim true'(doc) -> ["Check that memory data can be read and processed"]; -'+Mim true'(suite) -> []; +%% Check that memory data can be read and processed '+Mim true'(Config) when is_list(Config) -> - ?line Node = start_slave("+Mim true"), - ?line MD = rpc:call(Node, instrument, memory_data, []), - ?line [{total,[{sizes,S1,S2,S3},{blocks,B1,B2,B3}]}] + Node = start_slave("+Mim true"), + MD = rpc:call(Node, instrument, memory_data, []), + [{total,[{sizes,S1,S2,S3},{blocks,B1,B2,B3}]}] = rpc:call(Node, instrument, memory_status, [total]), - ?line stop_slave(Node), - ?line true = S1 =< S2, - ?line true = S2 =< S3, - ?line true = B1 =< B2, - ?line true = B2 =< B3, - ?line MDS = instrument:sort(MD), - ?line {Low, High} = instrument:mem_limits(MDS), - ?line true = Low < High, - ?line {_, AL} = MDS, - ?line SumBlocks = instrument:sum_blocks(MD), - ?line case SumBlocks of - N when is_integer(N) -> - ?line N = lists:foldl(fun ({_,_,Size,_}, Sum) -> - Size+Sum - end, - 0, - AL), - ?line N =< S3; - Other -> - ?line ?t:fail(Other) - end, - ?line lists:foldl( - fun ({TDescr,Addr,Size,Proc}, MinAddr) -> - ?line true = TDescr /= invalid_type, - ?line true = is_integer(TDescr), - ?line true = is_integer(Addr), - ?line true = is_integer(Size), - ?line true = Addr >= MinAddr, - ?line case Proc of - {0, Number, Serial} -> - ?line true = is_integer(Number), - ?line true = is_integer(Serial); - undefined -> - ok; - BadProc -> - ?line ?t:fail({badproc, BadProc}) - end, - ?line NextMinAddr = Addr+Size, - ?line true = NextMinAddr =< High, - ?line NextMinAddr - end, - Low, - AL), - ?line {_, DAL} = instrument:descr(MDS), - ?line lists:foreach( - fun ({TDescr,_,_,Proc}) -> - ?line true = TDescr /= invalid_type, - ?line true = is_atom(TDescr) orelse is_list(TDescr), - ?line true = is_pid(Proc) orelse Proc == undefined - end, - DAL), - ?line ASL = lists:map(fun ({_,A,S,_}) -> {A,S} end, AL), - ?line ASL = lists:map(fun ({_,A,S,_}) -> {A,S} end, DAL), - ?line instrument:holes(MDS), - ?line {comment, - "total status - sum of blocks = " ++ integer_to_list(S1-SumBlocks)}. - -'+Mis true'(doc) -> ["Check that memory data can be read and processed"]; -'+Mis true'(suite) -> []; + stop_slave(Node), + true = S1 =< S2, + true = S2 =< S3, + true = B1 =< B2, + true = B2 =< B3, + MDS = instrument:sort(MD), + {Low, High} = instrument:mem_limits(MDS), + true = Low < High, + {_, AL} = MDS, + SumBlocks = instrument:sum_blocks(MD), + case SumBlocks of + N when is_integer(N) -> + N = lists:foldl(fun ({_,_,Size,_}, Sum) -> + Size+Sum + end, 0, AL), + true = N =< S3; + Other -> + ct:fail(Other) + end, + lists:foldl( + fun ({TDescr,Addr,Size,Proc}, MinAddr) -> + true = TDescr /= invalid_type, + true = is_integer(TDescr), + true = is_integer(Addr), + true = is_integer(Size), + true = Addr >= MinAddr, + case Proc of + {0, Number, Serial} -> + true = is_integer(Number), + true = is_integer(Serial); + undefined -> + ok; + BadProc -> + ct:fail({badproc, BadProc}) + end, + NextMinAddr = Addr+Size, + true = NextMinAddr =< High, + NextMinAddr + end, Low, AL), + {_, DAL} = instrument:descr(MDS), + lists:foreach( + fun ({TDescr,_,_,Proc}) -> + true = TDescr /= invalid_type, + true = is_atom(TDescr) orelse is_list(TDescr), + true = is_pid(Proc) orelse Proc == undefined + end, DAL), + ASL = lists:map(fun ({_,A,S,_}) -> {A,S} end, AL), + ASL = lists:map(fun ({_,A,S,_}) -> {A,S} end, DAL), + instrument:holes(MDS), + {comment, "total status - sum of blocks = " ++ integer_to_list(S1-SumBlocks)}. + +%% Check that memory data can be read and processed '+Mis true'(Config) when is_list(Config) -> - ?line Node = start_slave("+Mis true"), - ?line [{total,[{sizes,S1,S2,S3},{blocks,B1,B2,B3}]}] + Node = start_slave("+Mis true"), + [{total,[{sizes,S1,S2,S3},{blocks,B1,B2,B3}]}] = rpc:call(Node, instrument, memory_status, [total]), - ?line true = S1 =< S2, - ?line true = S2 =< S3, - ?line true = B1 =< B2, - ?line true = B2 =< B3, - ?line true = is_list(rpc:call(Node,instrument,memory_status,[allocators])), - ?line true = is_list(rpc:call(Node,instrument,memory_status,[classes])), - ?line true = is_list(rpc:call(Node,instrument,memory_status,[types])), - ?line ok. + true = S1 =< S2, + true = S2 =< S3, + true = B1 =< B2, + true = B2 =< B3, + true = is_list(rpc:call(Node,instrument,memory_status,[allocators])), + true = is_list(rpc:call(Node,instrument,memory_status,[classes])), + true = is_list(rpc:call(Node,instrument,memory_status,[types])), + ok. start_slave(Args) -> - ?line {A, B, C} = now(), - ?line MicroSecs = A*1000000000000 + B*1000000 + C, - ?line Name = "instr_" ++ integer_to_list(MicroSecs), - ?line Pa = filename:dirname(code:which(?MODULE)), - ?line {ok, Node} = ?t:start_node(list_to_atom(Name), - slave, - [{args, "-pa " ++ Pa ++ " " ++ Args}]), - ?line Node. + MicroSecs = erlang:monotonic_time(), + Name = "instr" ++ integer_to_list(MicroSecs), + Pa = filename:dirname(code:which(?MODULE)), + {ok, Node} = test_server:start_node(list_to_atom(Name), + slave, + [{args, "-pa " ++ Pa ++ " " ++ Args}]), + Node. stop_slave(Node) -> - ?line true = ?t:stop_node(Node). + true = test_server:stop_node(Node). diff --git a/lib/tools/test/lcnt_SUITE.erl b/lib/tools/test/lcnt_SUITE.erl index 010dffe138..d39a5deeab 100644 --- a/lib/tools/test/lcnt_SUITE.erl +++ b/lib/tools/test/lcnt_SUITE.erl @@ -1,76 +1,57 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% Copyright Ericsson AB 2010-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% 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 %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% -module(lcnt_SUITE). --include_lib("test_server/include/test_server.hrl"). +-include_lib("common_test/include/ct.hrl"). %% Test server specific exports --export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2]). --export([init_per_suite/1, end_per_suite/1]). +-export([all/0, suite/0]). -export([init_per_testcase/2, end_per_testcase/2]). %% Test cases --export([ - t_load/1, - t_conflicts/1, - t_locations/1, - t_swap_keys/1 - ]). - -%% Default timetrap timeout (set in init_per_testcase) --define(default_timeout, ?t:minutes(4)). - -init_per_suite(Config) when is_list(Config) -> - Config. - -end_per_suite(Config) when is_list(Config) -> - Config. +-export([t_load/1, + t_conflicts/1, + t_locations/1, + t_swap_keys/1]). init_per_testcase(_Case, Config) -> - Dog = ?t:timetrap(?default_timeout), - [{watchdog,Dog} | Config]. + Config. -end_per_testcase(_Case, Config) -> - Dog = ?config(watchdog, Config), - ?t:timetrap_cancel(Dog), +end_per_testcase(_Case, _Config) -> catch lcnt:stop(), ok. -suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> [t_load, t_conflicts, t_locations, t_swap_keys]. - -groups() -> []. - -init_per_group(_GroupName, Config) -> Config. - -end_per_group(_GroupName, Config) -> Config. +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,4}}]. +all() -> + [t_load, t_conflicts, t_locations, t_swap_keys]. %%---------------------------------------------------------------------- %% Tests %%---------------------------------------------------------------------- -t_load(suite) -> []; -t_load(doc) -> ["Load data from file."]; +%% Load data from file. t_load(Config) when is_list(Config) -> - Path = ?config(data_dir, Config), + Path = proplists:get_value(data_dir, Config), Files = [filename:join([Path,"big_bang_40.lcnt"]), filename:join([Path,"ehb_3_3_hist.lcnt"])], ok = t_load_file(Files), @@ -83,10 +64,9 @@ t_load_file([File|Files]) -> ok = lcnt:stop(), t_load_file(Files). -t_conflicts(suite) -> []; -t_conflicts(doc) -> ["API: conflicts"]; +%% API: conflicts t_conflicts(Config) when is_list(Config) -> - Path = ?config(data_dir, Config), + Path = proplists:get_value(data_dir, Config), Files = [filename:join([Path,"big_bang_40.lcnt"]), filename:join([Path,"ehb_3_3_hist.lcnt"])], ok = t_conflicts_file(Files), @@ -97,12 +77,12 @@ t_conflicts_file([File|Files]) -> {ok, _} = lcnt:start(), ok = lcnt:load(File), ok = lcnt:conflicts(), - THs = [-1, 0, 100, 1000], + THs = [-1, 5], Print = [name , id , type , entry , tries , colls , ratio , time , duration], Opts = [ [{sort, Sort}, {reverse, Rev}, {max_locks, ML}, {combine, Combine}, {thresholds, [TH]}, {print, [Print]}] || - Sort <- [name , id , type , tries , colls , ratio , time , entry], - ML <- [none, 1 , 32, 4096], + Sort <- [name , type , tries , colls , ratio , time], + ML <- [none, 32], Combine <- [true, false], TH <- [{tries, Tries} || Tries <- THs] ++ [{colls, Colls} || Colls <- THs] ++ [{time, Time} || Time <- THs], Rev <- [true, false] @@ -117,10 +97,9 @@ test_conflicts_opts([Opt|Opts]) -> ok = lcnt:conflicts(Opt), test_conflicts_opts(Opts). -t_locations(suite) -> []; -t_locations(doc) -> ["API: locations"]; +%% API: locations t_locations(Config) when is_list(Config) -> - Path = ?config(data_dir, Config), + Path = proplists:get_value(data_dir, Config), Files = [filename:join([Path,"big_bang_40.lcnt"]), filename:join([Path,"ehb_3_3_hist.lcnt"])], ok = t_locations_file(Files), @@ -131,12 +110,12 @@ t_locations_file([File|Files]) -> {ok, _} = lcnt:start(), ok = lcnt:load(File), ok = lcnt:locations(), - THs = [-1, 0, 100, 1000], + THs = [-1, 0, 100], Print = [name , id , type , entry , tries , colls , ratio , time , duration], Opts = [ [{full_id, Id}, {sort, Sort}, {max_locks, ML}, {combine, Combine}, {thresholds, [TH]}, {print, Print}] || Sort <- [name , id , type , tries , colls , ratio , time , entry], - ML <- [none, 1 , 64], + ML <- [none, 64], Combine <- [true, false], TH <- [{tries, Tries} || Tries <- THs] ++ [{colls, Colls} || Colls <- THs] ++ [{time, Time} || Time <- THs], Id <- [true, false] @@ -150,10 +129,9 @@ test_locations_opts([Opt|Opts]) -> ok = lcnt:locations(Opt), test_locations_opts(Opts). -t_swap_keys(suite) -> []; -t_swap_keys(doc) -> ["Test interchanging port/process id with class"]; +%% Test interchanging port/process id with class t_swap_keys(Config) when is_list(Config) -> - Path = ?config(data_dir, Config), + Path = proplists:get_value(data_dir, Config), Files = [filename:join([Path,"big_bang_40.lcnt"]), filename:join([Path,"ehb_3_3_hist.lcnt"])], ok = t_swap_keys_file(Files), @@ -168,12 +146,3 @@ t_swap_keys_file([File|Files]) -> ok = lcnt:conflicts(), ok = lcnt:stop(), t_swap_keys_file(Files). - - -%%---------------------------------------------------------------------- -%% Auxiliary tests -%%---------------------------------------------------------------------- - -%%---------------------------------------------------------------------- -%% Auxiliary -%%---------------------------------------------------------------------- diff --git a/lib/tools/test/make_SUITE.erl b/lib/tools/test/make_SUITE.erl index b1a65226de..e6284db8b8 100644 --- a/lib/tools/test/make_SUITE.erl +++ b/lib/tools/test/make_SUITE.erl @@ -1,30 +1,31 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% 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 %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% -module(make_SUITE). -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2, make_all/1, make_files/1]). + init_per_group/2,end_per_group/2, make_all/1, make_files/1]). -export([otp_6057_init/1, - otp_6057_a/1, otp_6057_b/1, otp_6057_c/1, - otp_6057_end/1]). + otp_6057_a/1, otp_6057_b/1, otp_6057_c/1, + otp_6057_end/1]). --include_lib("test_server/include/test_server.hrl"). +-include_lib("common_test/include/ct.hrl"). -include_lib("kernel/include/file.hrl"). @@ -43,7 +44,7 @@ all() -> groups() -> [{otp_6057,[],[otp_6057_a, otp_6057_b, - otp_6057_c]}]. + otp_6057_c]}]. init_per_suite(Config) -> Config. @@ -60,52 +61,50 @@ end_per_group(_GroupName, Config) -> test_files() -> ["test1", "test2", "test3", "test4"]. -make_all(suite) -> []; make_all(Config) when is_list(Config) -> - ?line Current = prepare_data_dir(Config), - ?line up_to_date = make:all(), - ?line ok = ensure_exists(test_files()), - ?line ok = ensure_exists(["test5"],".S"), % Emakefile: [{test5,['S']} - ?line file:set_cwd(Current), - ?line ensure_no_messages(), + Current = prepare_data_dir(Config), + up_to_date = make:all(), + ok = ensure_exists(test_files()), + ok = ensure_exists(["test5"],".S"), % Emakefile: [{test5,['S']} + file:set_cwd(Current), + ensure_no_messages(), ok. -make_files(suite) -> []; make_files(Config) when is_list(Config) -> - ?line Current = prepare_data_dir(Config), + Current = prepare_data_dir(Config), %% Make files that exist. - ?line Files = [test1, test2], - ?line up_to_date = make:files(Files), % ok files - ?line ok = ensure_exists(Files), + Files = [test1, test2], + up_to_date = make:files(Files), % ok files + ok = ensure_exists(Files), - ?line error = make:files([test1,test7]), % non existing file - ?line up_to_date = make:files([test1,test2],[debug_info]), % with option + error = make:files([test1,test7]), % non existing file + up_to_date = make:files([test1,test2],[debug_info]), % with option - ?line file:set_cwd(Current), - ?line ensure_no_messages(), + file:set_cwd(Current), + ensure_no_messages(), ok. %% Moves to the data directory of this suite, clean it from any object %% files (*.jam for a JAM emulator). Returns the previous directory. prepare_data_dir(Config) -> - ?line {ok, Current} = file:get_cwd(), - ?line {value, {data_dir, Dir}} = lists:keysearch(data_dir, 1, Config), - ?line file:set_cwd(Dir), - ?line {ok, Files} = file:list_dir("."), - ?line delete_obj(Files, code:objfile_extension()), - ?line ensure_no_messages(), + {ok, Current} = file:get_cwd(), + {value, {data_dir, Dir}} = lists:keysearch(data_dir, 1, Config), + file:set_cwd(Dir), + {ok, Files} = file:list_dir("."), + delete_obj(Files, code:objfile_extension()), + ensure_no_messages(), Current. delete_obj([File|Rest], ObjExt) -> - ?line case filename:extension(File) of - ObjExt -> file:delete(File); - ".S" -> file:delete(File); - _ -> ok - end, - ?line delete_obj(Rest, ObjExt); + case filename:extension(File) of + ObjExt -> file:delete(File); + ".S" -> file:delete(File); + _ -> ok + end, + delete_obj(Rest, ObjExt); delete_obj([], _) -> ok. @@ -119,26 +118,26 @@ ensure_exists([Name|Rest], ObjExt) when is_atom(Name) -> ensure_exists([atom_to_list(Name)|Rest], ObjExt); ensure_exists([Name|Rest], ObjExt) -> case filelib:is_regular(Name++ObjExt) of - true -> - ensure_exists(Rest, ObjExt); - false -> - Name++ObjExt + true -> + ensure_exists(Rest, ObjExt); + false -> + Name++ObjExt end; ensure_exists([], _) -> ok. otp_6057_init(Config) when is_list(Config) -> - ?line DataDir = ?config(data_dir, Config), - ?line PrivDir = ?config(priv_dir, Config), + DataDir = proplists:get_value(data_dir, Config), + PrivDir = proplists:get_value(priv_dir, Config), %% Create the directories PrivDir/otp_6057/src1, /src2 and /ebin Src1 = filename:join([PrivDir, otp_6057, src1]), Src2 = filename:join([PrivDir, otp_6057, src2]), Ebin = filename:join([PrivDir, otp_6057, ebin]), - ?line ok = file:make_dir(filename:join(PrivDir, otp_6057)), - ?line ok = file:make_dir(Src1), - ?line ok = file:make_dir(Src2), - ?line ok = file:make_dir(Ebin), + ok = file:make_dir(filename:join(PrivDir, otp_6057)), + ok = file:make_dir(Src1), + ok = file:make_dir(Src2), + ok = file:make_dir(Ebin), %% Copy test1.erl and test2.erl to src1, and test3.erl to src2 Test1orig = filename:join(DataDir, "test1.erl"), @@ -147,35 +146,32 @@ otp_6057_init(Config) when is_list(Config) -> Test1 = filename:join(Src1, "test1.erl"), Test2 = filename:join(Src1, "test2.erl"), Test3 = filename:join(Src2, "test3.erl"), - ?line {ok, _} = file:copy(Test1orig, Test1), - ?line {ok, _} = file:copy(Test2orig, Test2), - ?line {ok, _} = file:copy(Test3orig, Test3), + {ok, _} = file:copy(Test1orig, Test1), + {ok, _} = file:copy(Test2orig, Test2), + {ok, _} = file:copy(Test3orig, Test3), %% Create an Emakefile in src1 Emakefile = filename:join(Src1, "Emakefile"), - ?line {ok, Fd} = file:open(Emakefile, write), - ?line ok = io:write(Fd, {["test1.erl","test2","../src2/test3"], - [{outdir,"../ebin"}]}), - ?line ok = io:fwrite(Fd, ".~n", []), - ?line ok = file:close(Fd), + {ok, Fd} = file:open(Emakefile, write), + ok = io:write(Fd, {["test1.erl","test2","../src2/test3"], + [{outdir,"../ebin"}]}), + ok = io:fwrite(Fd, ".~n", []), + ok = file:close(Fd), - ?line ensure_no_messages(), + ensure_no_messages(), Config. -otp_6057_a(suite) -> - []; -otp_6057_a(doc) -> - ["Test that make:all/0, suite/0 looks for object file in correct place"]; +%% Test that make:all/0, suite/0 looks for object file in correct place otp_6057_a(Config) when is_list(Config) -> - ?line PrivDir = ?config(priv_dir, Config), + PrivDir = proplists:get_value(priv_dir, Config), %% Go to src1, saving old CWD - ?line {ok, CWD} = file:get_cwd(), + {ok, CWD} = file:get_cwd(), Src1 = filename:join([PrivDir, otp_6057, src1]), - ?line ok = file:set_cwd(Src1), + ok = file:set_cwd(Src1), %% Call make:all() - ?line up_to_date = make:all(), + up_to_date = make:all(), %% Ensure that all beam files are created in the ebin directory Ebin = filename:join([PrivDir, otp_6057, ebin]), @@ -183,109 +179,103 @@ otp_6057_a(Config) when is_list(Config) -> Test2 = filename:join(Ebin, test2), Test3 = filename:join(Ebin, test3), case ensure_exists([Test1, Test2, Test3]) of - ok -> ok; - Missing -> - ?line ?t:fail({"missing beam file", Missing}) + ok -> ok; + Missing -> + ct:fail({"missing beam file", Missing}) end, %% Check creation date of test1.beam and make sure it is not %% recompiled if make:all() is called again. %% (Sleep a while, if the file is recompiled within a second then %% mtime will be the same). - ?line {ok, FileInfo1} = file:read_file_info(Test1++".beam"), + {ok, FileInfo1} = file:read_file_info(Test1++".beam"), Date1 = FileInfo1#file_info.mtime, - ?t:sleep(?t:seconds(2)), - ?line up_to_date = make:all(), - ?line {ok, FileInfo2} = file:read_file_info(Test1++".beam"), + timer:sleep(2000), + up_to_date = make:all(), + {ok, FileInfo2} = file:read_file_info(Test1++".beam"), case FileInfo2#file_info.mtime of - Date1 -> ok; - _Date2 -> - ?line ?t:fail({"recompiled beam file", Test1++".beam"}) + Date1 -> ok; + _Date2 -> + ct:fail({"recompiled beam file", Test1++".beam"}) end, %% Remove the beam files - ?line ok = - ensure_removed([Test1++".beam",Test2++".beam",Test2++".beam"]), + ok = + ensure_removed([Test1++".beam",Test2++".beam",Test2++".beam"]), %% Return to original CWD - ?line ok = file:set_cwd(CWD), + ok = file:set_cwd(CWD), - ?line ensure_no_messages(), + ensure_no_messages(), ok. -otp_6057_b(suite) -> - []; -otp_6057_b(doc) -> - ["Test that make:files/1 can handle a file in another directory"]; +%% Test that make:files/1 can handle a file in another directory otp_6057_b(Config) when is_list(Config) -> - ?line PrivDir = ?config(priv_dir, Config), + PrivDir = proplists:get_value(priv_dir, Config), %% Go to src1, saving old CWD - ?line {ok, CWD} = file:get_cwd(), + {ok, CWD} = file:get_cwd(), Src1 = filename:join([PrivDir, otp_6057, src1]), - ?line ok = file:set_cwd(Src1), + ok = file:set_cwd(Src1), %% Ensure there is no beam file already Ebin = filename:join([PrivDir, otp_6057, ebin]), Test3 = filename:join(Ebin, "test3"), - ?line ok = ensure_removed([Test3++".beam"]), + ok = ensure_removed([Test3++".beam"]), %% Call make:files/1 - ?line up_to_date = make:files(["../src2/test3"]), - + up_to_date = make:files(["../src2/test3"]), + %% Ensure that the beam file is created in the ebin directory case ensure_exists([Test3]) of - ok -> ok; - Missing -> - ?line ?t:fail({"missing beam file", Missing}) + ok -> ok; + Missing -> + ct:fail({"missing beam file", Missing}) end, %% Remove the beam file - ?line ok = ensure_removed([Test3++".beam"]), + ok = ensure_removed([Test3++".beam"]), %% Return to original CWD - ?line ok = file:set_cwd(CWD), + ok = file:set_cwd(CWD), - ?line ensure_no_messages(), + ensure_no_messages(), ok. -otp_6057_c(suite) -> - []; -otp_6057_c(doc) -> - ["Test that make:files/1 find options in Emakefile if a file is " - "given with the .erl extension there"]; +%% Test that make:files/1 find options in Emakefile if a file is +%% given with the .erl extension there otp_6057_c(Config) when is_list(Config) -> - ?line PrivDir = ?config(priv_dir, Config), + PrivDir = proplists:get_value(priv_dir, Config), %% Go to src1, saving old CWD - ?line {ok, CWD} = file:get_cwd(), + {ok, CWD} = file:get_cwd(), Src1 = filename:join([PrivDir, otp_6057, src1]), - ?line ok = file:set_cwd(Src1), + ok = file:set_cwd(Src1), %% Ensure there are no beam files already Ebin = filename:join([PrivDir, otp_6057, ebin]), Test1 = filename:join(Ebin, "test1"), Test2 = filename:join(Ebin, "test2"), - ?line ok = ensure_removed([Test1++".beam",Test2++".beam"]), + ok = ensure_removed([Test1++".beam",Test2++".beam"]), %% Call make:files/1 - ?line up_to_date = make:files([test1, test2]), - + up_to_date = make:files([test1, test2]), + %% Ensure that the beam files are created in the ebin directory Ebin = filename:join([PrivDir, otp_6057, ebin]), case ensure_exists([Test1, Test2]) of - ok -> ok; - Missing -> - ?line ?t:fail({"missing beam file", Missing}) + ok -> ok; + Missing -> + ct:fail({"missing beam file", Missing}) end, %% Remove the beam files - ?line ok = ensure_removed([Test1++".beam", Test2++".beam"]), + ok = ensure_removed([Test1++".beam", Test2++".beam"]), %% Return to original CWD - ?line ok = file:set_cwd(CWD), + ok = file:set_cwd(CWD), - ?line ensure_no_messages(), + ensure_no_messages(), ok. otp_6057_end(Config) when is_list(Config) -> @@ -302,13 +292,12 @@ ensure_no_messages() -> ensure_no_messages(N) -> receive - Any -> - io:format("Unexpected message: ~p", [Any]), - ensure_no_messages(N+1) + Any -> + io:format("Unexpected message: ~p", [Any]), + ensure_no_messages(N+1) after 0 -> - case N of - 0 -> ok; - N -> ?t:fail() - end + case N of + 0 -> ok; + N -> ct:fail(failed) + end end. - diff --git a/lib/tools/test/make_SUITE_data/Emakefile b/lib/tools/test/make_SUITE_data/Emakefile index ae9abb3cbe..9b35a1af93 100644 --- a/lib/tools/test/make_SUITE_data/Emakefile +++ b/lib/tools/test/make_SUITE_data/Emakefile @@ -1,13 +1,14 @@ -%% ``The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved via the world wide web at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% ``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. %% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB. %% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings diff --git a/lib/tools/test/tools_SUITE.erl b/lib/tools/test/tools_SUITE.erl index e3582b995b..b50f67a06a 100644 --- a/lib/tools/test/tools_SUITE.erl +++ b/lib/tools/test/tools_SUITE.erl @@ -1,77 +1,49 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% 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 %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% %% -module(tools_SUITE). --include_lib("test_server/include/test_server.hrl"). +-include_lib("common_test/include/ct.hrl"). -%% Default timetrap timeout (set in init_per_testcase). --define(default_timeout, ?t:minutes(1)). -define(application, tools). %% Test server specific exports --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2]). --export([init_per_testcase/2, end_per_testcase/2]). +-export([all/0, suite/0]). %% Test cases must be exported. -export([app_test/1, appup_test/1]). -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,1}}]. all() -> [app_test, appup_test]. -groups() -> - []. - -init_per_suite(Config) -> - Config. - -end_per_suite(_Config) -> - ok. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -init_per_testcase(_Case, Config) -> - ?line Dog=test_server:timetrap(?default_timeout), - [{watchdog, Dog}|Config]. -end_per_testcase(_Case, Config) -> - Dog=?config(watchdog, Config), - test_server:timetrap_cancel(Dog), - ok. - %%% %%% Test cases starts here. %%% -app_test(doc) -> - ["Test that the .app file does not contain any `basic' errors"]; -app_test(suite) -> - []; +%% Test that the .app file does not contain any `basic' errors app_test(Config) when is_list(Config) -> - ?line ?t:app_test(tools, tolerant). + test_server:app_test(tools, tolerant). %% Test that the .appup file does not contain any `basic' errors appup_test(Config) when is_list(Config) -> - ok = ?t:appup_test(tools). + ok = test_server:appup_test(tools). diff --git a/lib/tools/test/xref_SUITE.erl b/lib/tools/test/xref_SUITE.erl index 6870aefe5c..ce30fb711a 100644 --- a/lib/tools/test/xref_SUITE.erl +++ b/lib/tools/test/xref_SUITE.erl @@ -1,18 +1,19 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2013. All Rights Reserved. +%% Copyright Ericsson AB 2000-2016. All Rights Reserved. %% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. +%% 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 %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% 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. %% %% %CopyrightEnd% @@ -29,48 +30,43 @@ -define(privdir, "xref_SUITE_priv"). -define(copydir, "xref_SUITE_priv/datacopy"). -else. --include_lib("test_server/include/test_server.hrl"). +-include_lib("common_test/include/ct.hrl"). -define(format(S, A), ok). --define(datadir, ?config(data_dir, Conf)). --define(privdir, ?config(priv_dir, Conf)). --define(copydir, ?config(copy_dir, Conf)). +-define(datadir, proplists:get_value(data_dir, Conf)). +-define(privdir, proplists:get_value(priv_dir, Conf)). +-define(copydir, proplists:get_value(copy_dir, Conf)). -endif. --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2, init/1, fini/1]). +-export([all/0, suite/0, groups/0, + init_per_suite/1, end_per_suite/1]). --export([ - addrem/1, convert/1, intergraph/1, lines/1, loops/1, - no_data/1, modules/1]). +-export([addrem/1, convert/1, intergraph/1, lines/1, loops/1, + no_data/1, modules/1]). --export([ - add/1, default/1, info/1, lib/1, read/1, read2/1, remove/1, - replace/1, update/1, deprecated/1, trycatch/1, +-export([add/1, default/1, info/1, lib/1, read/1, read2/1, remove/1, + replace/1, update/1, deprecated/1, trycatch/1, fun_mfa/1, fun_mfa_r14/1, - fun_mfa_vars/1, qlc/1]). + fun_mfa_vars/1, qlc/1]). --export([ - analyze/1, basic/1, md/1, q/1, variables/1, unused_locals/1]). +-export([analyze/1, basic/1, md/1, q/1, variables/1, unused_locals/1]). --export([ - format_error/1, otp_7423/1, otp_7831/1, otp_10192/1]). +-export([format_error/1, otp_7423/1, otp_7831/1, otp_10192/1]). -import(lists, [append/2, flatten/1, keysearch/3, member/2, sort/1, usort/1]). -import(sofs, [converse/1, from_term/1, intersection/2, is_sofs_set/1, - range/1, relation_to_family/1, set/1, to_external/1, - union/2]). - --export([init_per_testcase/2, end_per_testcase/2]). + range/1, relation_to_family/1, set/1, to_external/1, + union/2]). %% Checks some info counters of a server and some relations that should hold. -export([check_count/1, check_state/1]). -include_lib("kernel/include/file.hrl"). - -include_lib("tools/src/xref.hrl"). -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,2}}]. all() -> [{group, xref}, {group, files}, {group, analyses}, @@ -88,48 +84,24 @@ groups() -> [analyze, basic, md, q, variables, unused_locals]}, {misc, [], [format_error, otp_7423, otp_7831, otp_10192]}]. -init_per_suite(Config) -> - init(Config). - -end_per_suite(_Config) -> - ok. - -init_per_group(_GroupName, Config) -> - Config. -end_per_group(_GroupName, Config) -> - Config. - - -init(Conf) when is_list(Conf) -> +init_per_suite(Conf) when is_list(Conf) -> DataDir = ?datadir, PrivDir = ?privdir, - ?line CopyDir = fname(PrivDir, "datacopy"), - ?line TarFile = fname(PrivDir, "datacopy.tgz"), - ?line {ok, Tar} = erl_tar:open(TarFile, [write, compressed]), - ?line ok = erl_tar:add(Tar, DataDir, CopyDir, [compressed]), - ?line ok = erl_tar:close(Tar), - ?line ok = erl_tar:extract(TarFile, [compressed]), - ?line ok = file:delete(TarFile), - [{copy_dir, CopyDir} | Conf]. - -fini(Conf) when is_list(Conf) -> - %% Nothing. - Conf. - -init_per_testcase(_Case, Config) -> - Dog=?t:timetrap(?t:minutes(2)), - [{watchdog, Dog}|Config]. - -end_per_testcase(_Case, _Config) -> - Dog=?config(watchdog, _Config), - test_server:timetrap_cancel(Dog), + CopyDir = fname(PrivDir, "datacopy"), + TarFile = fname(PrivDir, "datacopy.tgz"), + {ok, Tar} = erl_tar:open(TarFile, [write, compressed]), + ok = erl_tar:add(Tar, DataDir, CopyDir, [compressed]), + ok = erl_tar:close(Tar), + ok = erl_tar:extract(TarFile, [compressed]), + ok = file:delete(TarFile), + [{copy_dir, CopyDir}|Conf]. + +end_per_suite(Conf) when is_list(Conf) -> ok. - %% Seems a bit short... -addrem(suite) -> []; -addrem(doc) -> ["Simple test of removing modules"]; +%% Simple test of removing modules addrem(Conf) when is_list(Conf) -> S0 = new(), @@ -148,8 +120,8 @@ addrem(Conf) when is_list(Conf) -> LCallAt_m1 = [], XCallAt_m1 = [{E1,13}], Info1 = #xref_mod{name = m1, app_name = [a1]}, - ?line S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, - XC_m1, LC_m1), + S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, + XC_m1, LC_m1), D2 = {F2,7}, DefAt_m2 = [D2], @@ -160,26 +132,25 @@ addrem(Conf) when is_list(Conf) -> LCallAt_m2 = [], XCallAt_m2 = [{E2,96}], Info2 = #xref_mod{name = m2, app_name = [a2]}, - ?line S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, - XC_m2, LC_m2), - - ?line S5 = set_up(S2), - - ?line {ok, XMod1, S6} = remove_module(S5, m1), - ?line [a1] = XMod1#xref_mod.app_name, - ?line {ok, XMod2, S6a} = remove_module(S6, m2), - ?line [a2] = XMod2#xref_mod.app_name, - ?line S7 = set_up(S6a), - - ?line AppInfo1 = #xref_app{name = a1, rel_name = [r1]}, - ?line S9 = add_application(S7, AppInfo1), - ?line S10 = set_up(S9), - ?line AppInfo2 = #xref_app{name = a2, rel_name = [r1]}, - ?line _S11 = add_application(S10, AppInfo2), + S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, + XC_m2, LC_m2), + + S5 = set_up(S2), + + {ok, XMod1, S6} = remove_module(S5, m1), + [a1] = XMod1#xref_mod.app_name, + {ok, XMod2, S6a} = remove_module(S6, m2), + [a2] = XMod2#xref_mod.app_name, + S7 = set_up(S6a), + + AppInfo1 = #xref_app{name = a1, rel_name = [r1]}, + S9 = add_application(S7, AppInfo1), + S10 = set_up(S9), + AppInfo2 = #xref_app{name = a2, rel_name = [r1]}, + _S11 = add_application(S10, AppInfo2), ok. -convert(suite) -> []; -convert(doc) -> ["Coercion of data"]; +%% Coercion of data convert(Conf) when is_list(Conf) -> S0 = new(), @@ -214,8 +185,8 @@ convert(Conf) when is_list(Conf) -> LCallAt_m1 = [], XCallAt_m1 = [{E1,13},{E2,17},{E4,7}], Info1 = #xref_mod{name = m1, app_name = [a1]}, - ?line S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, - XC_m1, LC_m1), + S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, + XC_m1, LC_m1), D2 = {F2,7}, D3 = {F3,9}, @@ -228,8 +199,8 @@ convert(Conf) when is_list(Conf) -> LCallAt_m2 = [], XCallAt_m2 = [{E3,96},{E6,12},{UE1,77}], Info2 = #xref_mod{name = m2, app_name = [a2]}, - ?line S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, - XC_m2, LC_m2), + S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, + XC_m2, LC_m2), D4 = {F4,6}, D5 = {F5,97}, @@ -241,74 +212,74 @@ convert(Conf) when is_list(Conf) -> LCallAt_m3 = [{E5,19}], XCallAt_m3 = [{UE2,22}], Info3 = #xref_mod{name = m3, app_name = [a3]}, - ?line S3 = add_module(S2, Info3, DefAt_m3, X_m3, LCallAt_m3, XCallAt_m3, - XC_m3, LC_m3), + S3 = add_module(S2, Info3, DefAt_m3, X_m3, LCallAt_m3, XCallAt_m3, + XC_m3, LC_m3), Info4 = #xref_mod{name = m4, app_name = [a2]}, - ?line S4 = add_module(S3, Info4, [], [], [], [], [], []), + S4 = add_module(S3, Info4, [], [], [], [], [], []), AppInfo1 = #xref_app{name = a1, rel_name = [r1]}, - ?line S9 = add_application(S4, AppInfo1), + S9 = add_application(S4, AppInfo1), AppInfo2 = #xref_app{name = a2, rel_name = [r1]}, - ?line S10 = add_application(S9, AppInfo2), + S10 = add_application(S9, AppInfo2), AppInfo3 = #xref_app{name = a3, rel_name = [r2]}, - ?line S11 = add_application(S10, AppInfo3), + S11 = add_application(S10, AppInfo3), RelInfo1 = #xref_rel{name = r1}, - ?line S12 = add_release(S11, RelInfo1), + S12 = add_release(S11, RelInfo1), RelInfo2 = #xref_rel{name = r2}, - ?line S13 = add_release(S12, RelInfo2), + S13 = add_release(S12, RelInfo2), - ?line S = set_up(S13), + S = set_up(S13), - ?line {ok, _} = eval("(Lin)(m1->m1:Mod) * m1->m1", type_error, S), - ?line {ok, _} = eval("(XXL)(Lin)(m1->m1:Mod) * m1->m1", type_error, S), + {ok, _} = eval("(Lin)(m1->m1:Mod) * m1->m1", type_error, S), + {ok, _} = eval("(XXL)(Lin)(m1->m1:Mod) * m1->m1", type_error, S), - ?line AllDefAt = eval("(Lin) M", S), - ?line AllV = eval("(Fun) M", S), - ?line AllCallAt = eval("(XXL)(Lin) E", S), - ?line AllE = eval("E", S), + AllDefAt = eval("(Lin) M", S), + AllV = eval("(Fun) M", S), + AllCallAt = eval("(XXL)(Lin) E", S), + AllE = eval("E", S), - ?line AM = eval("AM", S), - ?line A = eval("A", S), - ?line R = eval("R", S), + AM = eval("AM", S), + A = eval("A", S), + R = eval("R", S), % vertices % general 1 step - ?line {ok, _} = eval("(Fun) (Lin) M", AllV, S), - ?line {ok, _} = eval("(Fun) (Lin) (Lin) M", AllV, S), - ?line {ok, _} = eval(f("(Fun) (Lin) ~p", [[F1, F3]]), [F1,F3], S), - ?line {ok, _} = eval(f("(Mod) ~p", [AllV]), [m1,m17,m2,m3], S), - ?line {ok, _} = eval(f("(Mod) ~p", [[F1,F3,F6]]), [m1,m2], S), - ?line {ok, _} = eval("(App) M", A, S), - ?line {ok, _} = eval(f("(App) ~p", [[m1,m2,m4]]), [a1,a2], S), - ?line {ok, _} = eval(f("(Rel) ~p", [A]), R, S), - ?line {ok, _} = eval(f("(Rel) ~p", [[a1,a2,a2]]), [r1], S), + {ok, _} = eval("(Fun) (Lin) M", AllV, S), + {ok, _} = eval("(Fun) (Lin) (Lin) M", AllV, S), + {ok, _} = eval(f("(Fun) (Lin) ~p", [[F1, F3]]), [F1,F3], S), + {ok, _} = eval(f("(Mod) ~p", [AllV]), [m1,m17,m2,m3], S), + {ok, _} = eval(f("(Mod) ~p", [[F1,F3,F6]]), [m1,m2], S), + {ok, _} = eval("(App) M", A, S), + {ok, _} = eval(f("(App) ~p", [[m1,m2,m4]]), [a1,a2], S), + {ok, _} = eval(f("(Rel) ~p", [A]), R, S), + {ok, _} = eval(f("(Rel) ~p", [[a1,a2,a2]]), [r1], S), % general 2 steps - ?line {ok, _} = eval("(Mod) (Lin) M", [m1,m17,m2,m3], S), - ?line {ok, _} = eval(f("(App) ~p", [AllV]), [a1,a2,a3], S), - ?line {ok, _} = eval("(Rel) M", R, S), + {ok, _} = eval("(Mod) (Lin) M", [m1,m17,m2,m3], S), + {ok, _} = eval(f("(App) ~p", [AllV]), [a1,a2,a3], S), + {ok, _} = eval("(Rel) M", R, S), % general 4 steps - ?line {ok, _} = eval("(Rel) (Lin) M", [r1,r2], S), + {ok, _} = eval("(Rel) (Lin) M", [r1,r2], S), % special 1 step - ?line {ok, _} = eval(f("(Lin) ~p", [AllV]), AllDefAt, S), - ?line {ok, _} = eval(f("(Lin) ~p", [[F1,F3]]), [{F1,12},{F3,9}], S), - ?line {ok, _} = eval("(Fun) M", AllV, S), - ?line {ok, _} = eval(f("(Fun) ~p", [[m1,m2]]), [F1,F2,F3,F6,F7,UF1], S), - ?line {ok, _} = eval(f("(Mod) ~p", [A]), AM, S), - ?line {ok, _} = eval(f("(Mod) ~p", [[a1,a2]]), [m1,m2,m4], S), - ?line {ok, _} = eval(f("(App) ~p", [R]), A, S), - ?line {ok, _} = eval(f("(App) ~p", [[r1]]), [a1,a2], S), + {ok, _} = eval(f("(Lin) ~p", [AllV]), AllDefAt, S), + {ok, _} = eval(f("(Lin) ~p", [[F1,F3]]), [{F1,12},{F3,9}], S), + {ok, _} = eval("(Fun) M", AllV, S), + {ok, _} = eval(f("(Fun) ~p", [[m1,m2]]), [F1,F2,F3,F6,F7,UF1], S), + {ok, _} = eval(f("(Mod) ~p", [A]), AM, S), + {ok, _} = eval(f("(Mod) ~p", [[a1,a2]]), [m1,m2,m4], S), + {ok, _} = eval(f("(App) ~p", [R]), A, S), + {ok, _} = eval(f("(App) ~p", [[r1]]), [a1,a2], S), % special 2 steps - ?line {ok, _} = eval("(Lin) M", AllDefAt, S), - ?line AnalyzedV = eval("(Fun) AM", S), - ?line {ok, _} = eval(f("(Fun) ~p", [A]), AnalyzedV, S), - ?line {ok, _} = eval(f("(Mod) ~p", [R]), AM, S), + {ok, _} = eval("(Lin) M", AllDefAt, S), + AnalyzedV = eval("(Fun) AM", S), + {ok, _} = eval(f("(Fun) ~p", [A]), AnalyzedV, S), + {ok, _} = eval(f("(Mod) ~p", [R]), AM, S), % special 4 steps - ?line AnalyzedAllDefAt = eval("(Lin) AM", S), - ?line {ok, _} = eval("(Lin) R", AnalyzedAllDefAt, S), + AnalyzedAllDefAt = eval("(Lin) AM", S), + {ok, _} = eval("(Lin) R", AnalyzedAllDefAt, S), % edges Ms = [{m1,m2},{m1,m3},{m2,m1},{m2,m3},{m3,m3}], @@ -318,31 +289,30 @@ convert(Conf) when is_list(Conf) -> Rs = [{r1,r1},{r1,r2},{r2,r2}], % general 1 step - ?line {ok, _} = eval("(Fun) (Lin) E", AllE, S), - ?line {ok, _} = eval(f("(Fun)(Lin) ~p", [[E1, E6]]), [E1, E6], S), - ?line {ok, _} = eval("(Mod) E", AllMs, S), - ?line {ok, _} = eval(f("(Mod) ~p", [[E1, E6]]), [{m1,m2},{m2,m3}], S), - ?line {ok, _} = eval(f("(App) ~p", [As]), As, S), - ?line {ok, _} = eval("(App) [m1->m2,m2->m3]", [{a1,a2},{a2,a3}], S), - ?line {ok, _} = eval(f("(Rel) ~p", [As]), Rs, S), - ?line {ok, _} = eval("(Rel) a1->a2", [{r1,r1}], S), + {ok, _} = eval("(Fun) (Lin) E", AllE, S), + {ok, _} = eval(f("(Fun)(Lin) ~p", [[E1, E6]]), [E1, E6], S), + {ok, _} = eval("(Mod) E", AllMs, S), + {ok, _} = eval(f("(Mod) ~p", [[E1, E6]]), [{m1,m2},{m2,m3}], S), + {ok, _} = eval(f("(App) ~p", [As]), As, S), + {ok, _} = eval("(App) [m1->m2,m2->m3]", [{a1,a2},{a2,a3}], S), + {ok, _} = eval(f("(Rel) ~p", [As]), Rs, S), + {ok, _} = eval("(Rel) a1->a2", [{r1,r1}], S), % special 1 step - ?line {ok, _} = eval("(XXL) (Lin) (Fun) E", AllCallAt, S), - ?line {ok, _} = eval("(XXL) (XXL) (Lin) (Fun) E", AllCallAt, S), - - ?line {ok, _} = eval(f("(XXL) (Lin) ~p", [[E1, E6]]), - [{{D1,D3},[13]}, {{D7,D4},[12]}], S), - ?line {ok, _} = eval(f("(Fun) ~p", [AllMs]), AllE, S), - ?line {ok, _} = eval("(Fun) [m1->m2,m2->m3]", [E1,E2,E6], S), - ?line {ok, _} = eval(f("(Mod) ~p", [As]), Ms, S), - ?line {ok, _} = eval("(Mod) [a1->a2,a2->a3]", [{m1,m2},{m2,m3}], S), - ?line {ok, _} = eval(f("(App) ~p", [Rs]), As, S), - ?line {ok, _} = eval("(App) r1->r1", [{a1,a2},{a2,a1}], S), + {ok, _} = eval("(XXL) (Lin) (Fun) E", AllCallAt, S), + {ok, _} = eval("(XXL) (XXL) (Lin) (Fun) E", AllCallAt, S), + + {ok, _} = eval(f("(XXL) (Lin) ~p", [[E1, E6]]), + [{{D1,D3},[13]}, {{D7,D4},[12]}], S), + {ok, _} = eval(f("(Fun) ~p", [AllMs]), AllE, S), + {ok, _} = eval("(Fun) [m1->m2,m2->m3]", [E1,E2,E6], S), + {ok, _} = eval(f("(Mod) ~p", [As]), Ms, S), + {ok, _} = eval("(Mod) [a1->a2,a2->a3]", [{m1,m2},{m2,m3}], S), + {ok, _} = eval(f("(App) ~p", [Rs]), As, S), + {ok, _} = eval("(App) r1->r1", [{a1,a2},{a2,a1}], S), ok. -intergraph(suite) -> []; -intergraph(doc) -> ["Inter Call Graph"]; +%% Inter Call Graph intergraph(Conf) when is_list(Conf) -> S0 = new(), @@ -391,8 +361,8 @@ intergraph(Conf) when is_list(Conf) -> LCallAt_m1 = [{E1,1},{E2,2},{E3,3},{E5,5},{E6,6},{E7,7}], XCallAt_m1 = [{E1,4}], Info1 = #xref_mod{name = m1, app_name = [a1]}, - ?line S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, - XC_m1, LC_m1), + S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, + XC_m1, LC_m1), D6 = {F6,6}, D7 = {F7,7}, @@ -408,73 +378,72 @@ intergraph(Conf) when is_list(Conf) -> LCallAt_m2 = [{E8,8},{E9,9},{E11,11},{E12,12},{E13,13},{E14,14}], XCallAt_m2 = [{E10,10},{E15,15}], Info2 = #xref_mod{name = m2, app_name = [a2]}, - ?line S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, - XC_m2, LC_m2), + S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, + XC_m2, LC_m2), AppInfo1 = #xref_app{name = a1, rel_name = [r1]}, - ?line S5 = add_application(S2, AppInfo1), + S5 = add_application(S2, AppInfo1), AppInfo2 = #xref_app{name = a2, rel_name = [r1]}, - ?line S6 = add_application(S5, AppInfo2), + S6 = add_application(S5, AppInfo2), RelInfo = #xref_rel{name = r1}, - ?line S7 = add_release(S6, RelInfo), + S7 = add_release(S6, RelInfo), - ?line S = set_up(S7), + S = set_up(S7), - ?line {ok, _} = eval("EE | m1", [E1,E5,E6,E7], S), - ?line {ok, _} = eval("EE | m2", [{F6,F1}], S), - ?line {ok, _} = eval("EE | m2 + EE | m2", [{F6,F1}], S), + {ok, _} = eval("EE | m1", [E1,E5,E6,E7], S), + {ok, _} = eval("EE | m2", [{F6,F1}], S), + {ok, _} = eval("EE | m2 + EE | m2", [{F6,F1}], S), - ?line {ok, _} = eval("(Fun)(Lin)(E | m1)", - to_external(union(set(XC_m1), set(LC_m1))), S), - ?line {ok, _} = eval("(XXL)(ELin) (EE | m1)", - [{{D2,D1},[1,2,4]},{{D4,D2},[5]},{{D5,D4},[6]},{{D4,D5},[7]}], - S), - ?line {ok, _} = eval("(XXL)(ELin)(EE | m2)", [{{D6,D1},[8,11,12]}], S), - ?line {ok, _} = eval("(XXL)(ELin)(ELin)(EE | m2)", - [{{D6,D1},[8,11,12]}], S), + {ok, _} = eval("(Fun)(Lin)(E | m1)", + to_external(union(set(XC_m1), set(LC_m1))), S), + {ok, _} = eval("(XXL)(ELin) (EE | m1)", + [{{D2,D1},[1,2,4]},{{D4,D2},[5]},{{D5,D4},[6]},{{D4,D5},[7]}], + S), + {ok, _} = eval("(XXL)(ELin)(EE | m2)", [{{D6,D1},[8,11,12]}], S), + {ok, _} = eval("(XXL)(ELin)(ELin)(EE | m2)", + [{{D6,D1},[8,11,12]}], S), %% Combining graphs (equal or different): - ?line {ok, _} = eval("(XXL)(ELin)(EE | m2 + EE | m2)", - [{{D6,D1},[8,11,12]}], S), - ?line {ok, _} = eval("(XXL)(ELin)(EE | m2 * EE | m2)", - [{{D6,D1},[8,11,12]}], S), - ?line {ok, _} = eval("(XXL)(ELin)(EE | m2 - EE | m1)", - [{{D6,D1},[8,11,12]}], S), - ?line {ok, _} = eval("(XXL)(ELin)(EE | m2 - E | m2)", - [{{D6,D1},[8,11,12]}], S), - ?line {ok, _} = eval("(XXL)(ELin)(Fun)(ELin)(EE | m2)", - [{{D6,D1},[8,11,12]}], S), - ?line {ok, _} = eval("EE | m1 + E | m1", LC_m1, S), - ?line {ok, _} = eval(f("EE | ~p + E | ~p", [F2, F2]), [E1,E2], S), + {ok, _} = eval("(XXL)(ELin)(EE | m2 + EE | m2)", + [{{D6,D1},[8,11,12]}], S), + {ok, _} = eval("(XXL)(ELin)(EE | m2 * EE | m2)", + [{{D6,D1},[8,11,12]}], S), + {ok, _} = eval("(XXL)(ELin)(EE | m2 - EE | m1)", + [{{D6,D1},[8,11,12]}], S), + {ok, _} = eval("(XXL)(ELin)(EE | m2 - E | m2)", + [{{D6,D1},[8,11,12]}], S), + {ok, _} = eval("(XXL)(ELin)(Fun)(ELin)(EE | m2)", + [{{D6,D1},[8,11,12]}], S), + {ok, _} = eval("EE | m1 + E | m1", LC_m1, S), + {ok, _} = eval(f("EE | ~p + E | ~p", [F2, F2]), [E1,E2], S), %% [1,4] from 'calls' is a subset of [1,2,4] from Inter Call Graph: - ?line {ok, _} = eval(f("(XXL)(Lin) (E | ~p)", [F2]), - [{{D2,D1},[1,4]},{{D2,D3},[2]}], S), - - ?line {ok, _} = eval(f("(XXL)(ELin) (EE | ~p)", [F2]), - [{{D2,D1},[1,2,4]}], S), - ?line {ok, _} = eval(f("(XXL)((ELin)(EE | ~p) + (Lin)(E | ~p))", [F2, F2]), - [{{D2,D1},[1,2,4]},{{D2,D3},[2]}], S), - ?line {ok, _} = - eval(f("(XXL)((ELin) ~p + (Lin) ~p)", [{F2, F1}, {F2, F1}]), - [{{D2,D1},[1,2,4]}], S), - ?line {ok, _} = eval(f("(Fun)(Lin) ~p", [{F2, F1}]), [E1], S), + {ok, _} = eval(f("(XXL)(Lin) (E | ~p)", [F2]), + [{{D2,D1},[1,4]},{{D2,D3},[2]}], S), + + {ok, _} = eval(f("(XXL)(ELin) (EE | ~p)", [F2]), + [{{D2,D1},[1,2,4]}], S), + {ok, _} = eval(f("(XXL)((ELin)(EE | ~p) + (Lin)(E | ~p))", [F2, F2]), + [{{D2,D1},[1,2,4]},{{D2,D3},[2]}], S), + {ok, _} = + eval(f("(XXL)((ELin) ~p + (Lin) ~p)", [{F2, F1}, {F2, F1}]), + [{{D2,D1},[1,2,4]}], S), + {ok, _} = eval(f("(Fun)(Lin) ~p", [{F2, F1}]), [E1], S), %% The external call E4 is included in the reply: - ?line {ok, _} = eval("(XXL)(Lin)(LC | m1)", - [{{D2,D1},[1,4]},{{D2,D3},[2]},{{D3,D1},[3]}, - {{D4,D2},[5]},{{D4,D5},[7]},{{D5,D4},[6]}], S), + {ok, _} = eval("(XXL)(Lin)(LC | m1)", + [{{D2,D1},[1,4]},{{D2,D3},[2]},{{D3,D1},[3]}, + {{D4,D2},[5]},{{D4,D5},[7]},{{D5,D4},[6]}], S), %% The local call E1 is included in the reply: - ?line {ok, _} = eval("(XXL)(Lin)(XC | m1)", [{{D2,D1},[1,4]}], S), + {ok, _} = eval("(XXL)(Lin)(XC | m1)", [{{D2,D1},[1,4]}], S), - ?line {ok, _} = eval(f("(LLin) (E | ~p || ~p) + (XLin) (E | ~p || ~p)", - [F2, F1, F2, F1]), [{E4,[1,4]}], S), + {ok, _} = eval(f("(LLin) (E | ~p || ~p) + (XLin) (E | ~p || ~p)", + [F2, F1, F2, F1]), [{E4,[1,4]}], S), - ?line {ok, _} = eval("# (ELin) E", 6, S), + {ok, _} = eval("# (ELin) E", 6, S), ok. -lines(suite) -> []; -lines(doc) -> ["More test of Inter Call Graph, and regular expressions"]; +%% More test of Inter Call Graph, and regular expressions lines(Conf) when is_list(Conf) -> S0 = new(), @@ -508,8 +477,8 @@ lines(Conf) when is_list(Conf) -> LCallAt_m1 = [{E1,1},{E3,3},{E6,6}], XCallAt_m1 = [{E2,2},{E4,4},{E5,5},{E7,7}], Info1 = #xref_mod{name = m1, app_name = [a1]}, - ?line S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, - XC_m1, LC_m1), + S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, + XC_m1, LC_m1), DefAt_m2 = [D4], X_m2 = [F4], @@ -519,81 +488,80 @@ lines(Conf) when is_list(Conf) -> LCallAt_m2 = [], XCallAt_m2 = [], Info2 = #xref_mod{name = m2, app_name = [a2]}, - ?line S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, - XC_m2, LC_m2), + S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, + XC_m2, LC_m2), AppInfo1 = #xref_app{name = a1, rel_name = [r1]}, - ?line S5 = add_application(S2, AppInfo1), + S5 = add_application(S2, AppInfo1), AppInfo2 = #xref_app{name = a2, rel_name = [r1]}, - ?line S6 = add_application(S5, AppInfo2), + S6 = add_application(S5, AppInfo2), RelInfo = #xref_rel{name = r1}, - ?line S7 = add_release(S6, RelInfo), - - ?line S = set_up(S7), - - ?line {ok, _} = eval("(XXL) (ELin) (EE | m1)", - [{{D1,D1},[1]},{{D1,D4},[1,4]},{{D3,D1},[3]},{{D3,D4},[3]}, - {{D5,D4},[6]}], S), - ?line {ok, _} = eval("(XXL)(Lin) (E | m1)", - [{{D1,D2},[1]},{{D1,D4},[4]},{{D2,D1},[2]}, - {{D2,D4},[5]},{{D3,D2},[3]},{{D5,D6},[6]},{{D6,D4},[7]}], - S), - ?line {ok, _} = eval("(E | m1) + (EE | m1)", - [E1,E2,E3,E4,E5,E6,E7,{F1,F1},{F3,F1},{F3,F4},{F5,F4}], - S), - ?line {ok, _} = eval("(Lin)(E | m1)", - [{E4,[4]},{E1,[1]},{E2,[2]},{E5,[5]}, - {E3,[3]},{E7,[7]},{E6,[6]}], S), - ?line {ok, _} = eval("(ELin)(EE | m1)", - [{{F1,F1},[1]},{{F1,F4},[1,4]},{{F3,F1},[3]},{{F3,F4},[3]}, - {{F5,F4},[6]}], S), - ?line {ok, _} = eval("(Lin)(E | m1) + (ELin)(EE | m1)", - [{E4,[1,4]},{E1,[1]},{E2,[2]},{E5,[5]}, - {E3,[3]},{E7,[7]},{E6,[6]}, - {{F1,F1},[1]},{{F3,F1},[3]},{{F3,F4},[3]}, - {{F5,F4},[6]}], S), - ?line {ok, _} = eval("(Lin)(E | m1) - (ELin)(EE | m1)", - [{E1,[1]},{E2,[2]},{E5,[5]}, - {E3,[3]},{E7,[7]},{E6,[6]}], S), - ?line {ok, _} = eval("(Lin)(E | m1) * (ELin)(EE | m1)", - [{E4,[4]}], S), - ?line {ok, _} = eval("(XXL)(Lin) (E | m1)", - [{{D1,D4},[4]},{{D1,D2},[1]},{{D2,D1},[2]},{{D2,D4},[5]}, - {{D3,D2},[3]},{{D6,D4},[7]},{{D5,D6},[6]}], S), - ?line {ok, _} = eval("(XXL)(ELin) (EE | m1)", - [{{D1,D1},[1]},{{D1,D4},[1,4]},{{D3,D1},[3]},{{D3,D4},[3]}, - {{D5,D4},[6]}], S), - ?line {ok, _} = eval("(XXL)(Lin)(Fun)(Lin) (E | m1)", - [{{D1,D4},[4]},{{D1,D2},[1]},{{D2,D1},[2]},{{D2,D4},[5]}, - {{D3,D2},[3]},{{D6,D4},[7]},{{D5,D6},[6]}], S), - ?line {ok, _} = eval("(XXL)(ELin)(Fun)(ELin) (EE | m1)", - [{{D1,D1},[1]},{{D1,D4},[1,4]},{{D3,D1},[3]},{{D3,D4},[3]}, - {{D5,D4},[6]}], S), + S7 = add_release(S6, RelInfo), + + S = set_up(S7), + + {ok, _} = eval("(XXL) (ELin) (EE | m1)", + [{{D1,D1},[1]},{{D1,D4},[1,4]},{{D3,D1},[3]},{{D3,D4},[3]}, + {{D5,D4},[6]}], S), + {ok, _} = eval("(XXL)(Lin) (E | m1)", + [{{D1,D2},[1]},{{D1,D4},[4]},{{D2,D1},[2]}, + {{D2,D4},[5]},{{D3,D2},[3]},{{D5,D6},[6]},{{D6,D4},[7]}], + S), + {ok, _} = eval("(E | m1) + (EE | m1)", + [E1,E2,E3,E4,E5,E6,E7,{F1,F1},{F3,F1},{F3,F4},{F5,F4}], + S), + {ok, _} = eval("(Lin)(E | m1)", + [{E4,[4]},{E1,[1]},{E2,[2]},{E5,[5]}, + {E3,[3]},{E7,[7]},{E6,[6]}], S), + {ok, _} = eval("(ELin)(EE | m1)", + [{{F1,F1},[1]},{{F1,F4},[1,4]},{{F3,F1},[3]},{{F3,F4},[3]}, + {{F5,F4},[6]}], S), + {ok, _} = eval("(Lin)(E | m1) + (ELin)(EE | m1)", + [{E4,[1,4]},{E1,[1]},{E2,[2]},{E5,[5]}, + {E3,[3]},{E7,[7]},{E6,[6]}, + {{F1,F1},[1]},{{F3,F1},[3]},{{F3,F4},[3]}, + {{F5,F4},[6]}], S), + {ok, _} = eval("(Lin)(E | m1) - (ELin)(EE | m1)", + [{E1,[1]},{E2,[2]},{E5,[5]}, + {E3,[3]},{E7,[7]},{E6,[6]}], S), + {ok, _} = eval("(Lin)(E | m1) * (ELin)(EE | m1)", + [{E4,[4]}], S), + {ok, _} = eval("(XXL)(Lin) (E | m1)", + [{{D1,D4},[4]},{{D1,D2},[1]},{{D2,D1},[2]},{{D2,D4},[5]}, + {{D3,D2},[3]},{{D6,D4},[7]},{{D5,D6},[6]}], S), + {ok, _} = eval("(XXL)(ELin) (EE | m1)", + [{{D1,D1},[1]},{{D1,D4},[1,4]},{{D3,D1},[3]},{{D3,D4},[3]}, + {{D5,D4},[6]}], S), + {ok, _} = eval("(XXL)(Lin)(Fun)(Lin) (E | m1)", + [{{D1,D4},[4]},{{D1,D2},[1]},{{D2,D1},[2]},{{D2,D4},[5]}, + {{D3,D2},[3]},{{D6,D4},[7]},{{D5,D6},[6]}], S), + {ok, _} = eval("(XXL)(ELin)(Fun)(ELin) (EE | m1)", + [{{D1,D1},[1]},{{D1,D4},[1,4]},{{D3,D1},[3]},{{D3,D4},[3]}, + {{D5,D4},[6]}], S), %% A few tests on regexp. - ?line {ok, _} = eval("\"(foo\":Mod", parse_error, S), - ?line {ok, _} = eval("_Foo:_/_", parse_error, S), - ?line {ok, _} = eval("\".*foo\"", parse_error, S), - ?line {ok, _} = eval("_:_/_:Lin", parse_error, S), - ?line {ok, _} = eval("_:_/_:Mod", parse_error, S), - ?line {ok, _} = eval("_:_/_:App", parse_error, S), - ?line {ok, _} = eval("_:_/_:Rel", parse_error, S), - ?line {ok, _} = eval("m2:_/4", [F4], S), - ?line {ok, _} = eval("m2:_/4:Fun", [F4], S), - ?line {ok, _} = eval("\"m.?\":\"f.*\"/\"6\"", [F6], S), - ?line {ok, _} = eval("_:_/6", [F6], S), - ?line {ok, _} = eval("m1:\"f1\"/_", [F1], S), - ?line {ok, _} = eval("\"m1\":f1/_", [F1], S), - ?line {ok, _} = eval("\"m1\":Mod", [m1], S), - ?line {ok, _} = eval("\"a1\":App", [a1], S), - ?line {ok, _} = eval("\"r1\":Rel", [r1], S), - ?line {ok, _} = eval("_:_/-1", [], S), + {ok, _} = eval("\"(foo\":Mod", parse_error, S), + {ok, _} = eval("_Foo:_/_", parse_error, S), + {ok, _} = eval("\".*foo\"", parse_error, S), + {ok, _} = eval("_:_/_:Lin", parse_error, S), + {ok, _} = eval("_:_/_:Mod", parse_error, S), + {ok, _} = eval("_:_/_:App", parse_error, S), + {ok, _} = eval("_:_/_:Rel", parse_error, S), + {ok, _} = eval("m2:_/4", [F4], S), + {ok, _} = eval("m2:_/4:Fun", [F4], S), + {ok, _} = eval("\"m.?\":\"f.*\"/\"6\"", [F6], S), + {ok, _} = eval("_:_/6", [F6], S), + {ok, _} = eval("m1:\"f1\"/_", [F1], S), + {ok, _} = eval("\"m1\":f1/_", [F1], S), + {ok, _} = eval("\"m1\":Mod", [m1], S), + {ok, _} = eval("\"a1\":App", [a1], S), + {ok, _} = eval("\"r1\":Rel", [r1], S), + {ok, _} = eval("_:_/-1", [], S), ok. -loops(suite) -> []; -loops(doc) -> ["More Inter Call Graph, loops and \"unusual\" cases"]; +%% More Inter Call Graph, loops and "unusual" cases loops(Conf) when is_list(Conf) -> S0 = new(), @@ -626,51 +594,49 @@ loops(Conf) when is_list(Conf) -> LCallAt_m1 = [{E2,2},{E3,3},{E4,4}], XCallAt_m1 = [{E1,1},{E5,5}], Info1 = #xref_mod{name = m1, app_name = [a1]}, - ?line S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, - XC_m1, LC_m1), + S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, + XC_m1, LC_m1), - ?line S = set_up(S1), + S = set_up(S1), % Neither F6 nor F7 is included. Perhaps one should change that? - ?line {ok, _} = eval("EE | m1", [E1,E2,{F3,F3}], S), - ?line {ok, _} = eval(f("(XXL)(ELin) (EE | ~p)", [F3]), [{{D3,D3},[3]}], S), + {ok, _} = eval("EE | m1", [E1,E2,{F3,F3}], S), + {ok, _} = eval(f("(XXL)(ELin) (EE | ~p)", [F3]), [{{D3,D3},[3]}], S), - ?line {ok, _} = eval("m1->m1 | m1->m1", type_error, S), - ?line {ok, _} = eval(f("~p | ~p", [F2, F1]), type_error, S), + {ok, _} = eval("m1->m1 | m1->m1", type_error, S), + {ok, _} = eval(f("~p | ~p", [F2, F1]), type_error, S), - ?line {ok, _} = eval(f("range (closure EE | ~p)", [F1]), [F1], S), - ?line {ok, _} = eval(f("domain (closure EE || ~p)", [F3]), [F3], S), + {ok, _} = eval(f("range (closure EE | ~p)", [F1]), [F1], S), + {ok, _} = eval(f("domain (closure EE || ~p)", [F3]), [F3], S), - ?line {ok, _} = eval(f("domain (closure E || ~p)", [F3]), [F3,F4,F5], S), + {ok, _} = eval(f("domain (closure E || ~p)", [F3]), [F3,F4,F5], S), - ?line {ok, _} = eval("components E", [[F1],[F2],[F3,F4,F5]], S), - ?line {ok, _} = eval("components EE", [[F1],[F2],[F3]], S), + {ok, _} = eval("components E", [[F1],[F2],[F3,F4,F5]], S), + {ok, _} = eval("components EE", [[F1],[F2],[F3]], S), ok. -no_data(suite) -> []; -no_data(doc) -> ["Simple tests when there is no data"]; +%% Simple tests when there is no data no_data(Conf) when is_list(Conf) -> S0 = new(), - ?line S1 = set_up(S0), - ?line {ok, _} = eval("M", [], S1), - ?line {ok, _} = eval("A", [], S1), - ?line {ok, _} = eval("R", [], S1), + S1 = set_up(S0), + {ok, _} = eval("M", [], S1), + {ok, _} = eval("A", [], S1), + {ok, _} = eval("R", [], S1), ModInfo = #xref_mod{name = m, app_name = []}, - ?line S2 = add_module(S1, ModInfo, [], [], [], [], [], []), + S2 = add_module(S1, ModInfo, [], [], [], [], [], []), AppInfo = #xref_app{name = a, rel_name = []}, - ?line S3 = add_application(S2, AppInfo), + S3 = add_application(S2, AppInfo), RelInfo = #xref_rel{name = r, dir = ""}, - ?line S4 = add_release(S3, RelInfo), - ?line S5 = set_up(S4), - ?line {ok, _} = eval("M", [m], S5), - ?line {ok, _} = eval("A", [a], S5), - ?line {ok, _} = eval("R", [r], S5), + S4 = add_release(S3, RelInfo), + S5 = set_up(S4), + {ok, _} = eval("M", [m], S5), + {ok, _} = eval("A", [a], S5), + {ok, _} = eval("R", [r], S5), ok. -modules(suite) -> []; -modules(doc) -> ["Modules mode"]; +%% Modules mode modules(Conf) when is_list(Conf) -> CopyDir = ?copydir, Dir = fname(CopyDir, "rel2"), @@ -683,34 +649,33 @@ modules(Conf) when is_list(Conf) -> Xbeam = fname(EB2, "x.beam"), Ybeam = fname(EB1_1, "y.beam"), - ?line {ok, x} = compile:file(X, [debug_info, {outdir,EB2}]), - ?line {ok, y} = compile:file(Y, [debug_info, {outdir,EB1_1}]), - - ?line {ok, S0} = xref_base:new([{xref_mode, modules}]), - ?line {ok, release2, S1} = - xref_base:add_release(S0, Dir, [{name,release2}]), - ?line S = set_up(S1), - ?line {{error, _, {unavailable_analysis, undefined_function_calls}}, _} = - xref_base:analyze(S, undefined_function_calls), - ?line {{error, _, {unavailable_analysis, locals_not_used}}, _} = - xref_base:analyze(S, locals_not_used), - ?line {{error, _, {unavailable_analysis, {call, foo}}}, _} = - xref_base:analyze(S, {call, foo}), - ?line {{error, _, {unavailable_analysis, {use, foo}}}, _} = - xref_base:analyze(S, {use, foo}), - ?line analyze(undefined_functions, [{x,undef,0}], S), - ?line 5 = length(xref_base:info(S)), + {ok, x} = compile:file(X, [debug_info, {outdir,EB2}]), + {ok, y} = compile:file(Y, [debug_info, {outdir,EB1_1}]), + + {ok, S0} = xref_base:new([{xref_mode, modules}]), + {ok, release2, S1} = + xref_base:add_release(S0, Dir, [{name,release2}]), + S = set_up(S1), + {{error, _, {unavailable_analysis, undefined_function_calls}}, _} = + xref_base:analyze(S, undefined_function_calls), + {{error, _, {unavailable_analysis, locals_not_used}}, _} = + xref_base:analyze(S, locals_not_used), + {{error, _, {unavailable_analysis, {call, foo}}}, _} = + xref_base:analyze(S, {call, foo}), + {{error, _, {unavailable_analysis, {use, foo}}}, _} = + xref_base:analyze(S, {use, foo}), + analyze(undefined_functions, [{x,undef,0}], S), + 5 = length(xref_base:info(S)), %% More: all info, conversions. - ?line ok = file:delete(Xbeam), - ?line ok = file:delete(Ybeam), - ?line ok = xref_base:delete(S), + ok = file:delete(Xbeam), + ok = file:delete(Ybeam), + ok = xref_base:delete(S), ok. -add(suite) -> []; -add(doc) -> ["Add modules, applications, releases, directories"]; +%% Add modules, applications, releases, directories add(Conf) when is_list(Conf) -> CopyDir = ?copydir, Dir = fname(CopyDir, "rel2"), @@ -726,116 +691,114 @@ add(Conf) when is_list(Conf) -> Xbeam = fname(EB2, "x.beam"), Ybeam = fname(EB1_1, "y.beam"), - ?line {ok, x} = compile:file(X, [debug_info, {outdir,EB2}]), - ?line {ok, y} = compile:file(Y, [debug_info, {outdir,EB1_1}]), - - ?line case os:type() of - {unix, _} -> - ?line make_udir(UDir), - ?line make_ufile(UFile); - _ -> - true - end, - - ?line {error, _, {invalid_options,[not_an_option] }} = - xref_base:new([not_an_option]), - ?line {error, _, {invalid_options,[{verbose,not_a_value}] }} = - xref_base:new([{verbose,not_a_value}]), - ?line S = new(), - ?line {error, _, {invalid_options,[not_an_option]}} = - xref_base:set_up(S, [not_an_option]), - ?line {error, _, {invalid_options,[{builtins,true},not_an_option]}} = - xref_base:add_directory(S, foo, [{builtins,true},not_an_option]), - ?line {error, _, {invalid_options,[{builtins,not_a_value}]}} = - xref_base:add_directory(S, foo, [{builtins,not_a_value}]), - ?line {error, _, {invalid_filename,{foo,bar}}} = - xref_base:add_directory(S, {foo,bar}, []), - ?line {error, _, {invalid_options,[{builtins,true},not_an_option]}} = - xref_base:add_module(S, foo, [{builtins,true},not_an_option]), - ?line {error, _, {invalid_options,[{builtins,not_a_value}]}} = - xref_base:add_module(S, foo, [{builtins,not_a_value}]), - ?line {error, _, {invalid_filename,{foo,bar}}} = - xref_base:add_module(S, {foo,bar}, []), - ?line {error, _, {invalid_options,[{builtins,true},not_an_option]}} = - xref_base:add_application(S, foo, [{builtins,true},not_an_option]), - ?line {error, _, {invalid_options,[{builtins,not_a_value}]}} = - xref_base:add_application(S, foo, [{builtins,not_a_value}]), - ?line {error, _, {invalid_filename,{foo,bar}}} = - xref_base:add_application(S, {foo,bar}, []), - ?line {error, _, {invalid_options,[not_an_option]}} = - xref_base:add_release(S, foo, [not_an_option]), - ?line {error, _, {invalid_options,[{builtins,not_a_value}]}} = - xref_base:add_release(S, foo, [{builtins,not_a_value}]), - ?line {error, _, {invalid_filename,{foo,bar}}} = - xref_base:add_release(S, {foo,bar}, []), - ?line {ok, S1} = - xref_base:set_default(S, [{verbose,false}, {warnings, false}]), - ?line case os:type() of - {unix, _} -> - ?line {error, _, {file_error, _, _}} = - xref_base:add_release(S, UDir); - _ -> - true - end, - ?line {error, _, {file_error, _, _}} = - xref_base:add_release(S, fname(["/a/b/c/d/e/f","__foo"])), - ?line {ok, release2, S2} = - xref_base:add_release(S1, Dir, [{name,release2}]), - ?line {error, _, {module_clash, {x, _, _}}} = - xref_base:add_module(S2, Xbeam), - ?line {ok, S3} = xref_base:remove_release(S2, release2), - ?line {ok, rel2, S4} = xref_base:add_release(S3, Dir), - ?line {error, _, {release_clash, {rel2, _, _}}} = - xref_base:add_release(S4, Dir), - ?line {ok, S5} = xref_base:remove_release(S4, rel2), + {ok, x} = compile:file(X, [debug_info, {outdir,EB2}]), + {ok, y} = compile:file(Y, [debug_info, {outdir,EB1_1}]), + + case os:type() of + {unix, _} -> + make_udir(UDir), + make_ufile(UFile); + _ -> + true + end, + + {error, _, {invalid_options,[not_an_option] }} = + xref_base:new([not_an_option]), + {error, _, {invalid_options,[{verbose,not_a_value}] }} = + xref_base:new([{verbose,not_a_value}]), + S = new(), + {error, _, {invalid_options,[not_an_option]}} = + xref_base:set_up(S, [not_an_option]), + {error, _, {invalid_options,[{builtins,true},not_an_option]}} = + xref_base:add_directory(S, foo, [{builtins,true},not_an_option]), + {error, _, {invalid_options,[{builtins,not_a_value}]}} = + xref_base:add_directory(S, foo, [{builtins,not_a_value}]), + {error, _, {invalid_filename,{foo,bar}}} = + xref_base:add_directory(S, {foo,bar}, []), + {error, _, {invalid_options,[{builtins,true},not_an_option]}} = + xref_base:add_module(S, foo, [{builtins,true},not_an_option]), + {error, _, {invalid_options,[{builtins,not_a_value}]}} = + xref_base:add_module(S, foo, [{builtins,not_a_value}]), + {error, _, {invalid_filename,{foo,bar}}} = + xref_base:add_module(S, {foo,bar}, []), + {error, _, {invalid_options,[{builtins,true},not_an_option]}} = + xref_base:add_application(S, foo, [{builtins,true},not_an_option]), + {error, _, {invalid_options,[{builtins,not_a_value}]}} = + xref_base:add_application(S, foo, [{builtins,not_a_value}]), + {error, _, {invalid_filename,{foo,bar}}} = + xref_base:add_application(S, {foo,bar}, []), + {error, _, {invalid_options,[not_an_option]}} = + xref_base:add_release(S, foo, [not_an_option]), + {error, _, {invalid_options,[{builtins,not_a_value}]}} = + xref_base:add_release(S, foo, [{builtins,not_a_value}]), + {error, _, {invalid_filename,{foo,bar}}} = + xref_base:add_release(S, {foo,bar}, []), + {ok, S1} = + xref_base:set_default(S, [{verbose,false}, {warnings, false}]), + case os:type() of + {unix, _} -> + {error, _, {file_error, _, _}} = + xref_base:add_release(S, UDir); + _ -> + true + end, + {error, _, {file_error, _, _}} = + xref_base:add_release(S, fname(["/a/b/c/d/e/f","__foo"])), + {ok, release2, S2} = + xref_base:add_release(S1, Dir, [{name,release2}]), + {error, _, {module_clash, {x, _, _}}} = + xref_base:add_module(S2, Xbeam), + {ok, S3} = xref_base:remove_release(S2, release2), + {ok, rel2, S4} = xref_base:add_release(S3, Dir), + {error, _, {release_clash, {rel2, _, _}}} = + xref_base:add_release(S4, Dir), + {ok, S5} = xref_base:remove_release(S4, rel2), %% One unreadable file and one JAM file found (no verification here): - ?line {ok, [], S6} = xref_base:add_directory(S5, fname(CopyDir,"dir"), - [{recurse,true}, {warnings,true}]), - ?line case os:type() of - {unix, _} -> - ?line {error, _, {file_error, _, _}} = - xref_base:add_directory(S6, UDir); - _ -> - true - end, - ?line {ok, app1, S7} = xref_base:add_application(S6, A1_1), - ?line {error, _, {application_clash, {app1, _, _}}} = - xref_base:add_application(S7, A1_1), - ?line {ok, S8} = xref_base:remove_application(S7, app1), - ?line ok = xref_base:delete(S8), - ?line ok = file:delete(Xbeam), - ?line ok = file:delete(Ybeam), - ?line case os:type() of - {unix, _} -> - ?line ok = file:del_dir(UDir), - ?line ok = file:delete(UFile); - _ -> - true - end, + {ok, [], S6} = xref_base:add_directory(S5, fname(CopyDir,"dir"), + [{recurse,true}, {warnings,true}]), + case os:type() of + {unix, _} -> + {error, _, {file_error, _, _}} = + xref_base:add_directory(S6, UDir); + _ -> + true + end, + {ok, app1, S7} = xref_base:add_application(S6, A1_1), + {error, _, {application_clash, {app1, _, _}}} = + xref_base:add_application(S7, A1_1), + {ok, S8} = xref_base:remove_application(S7, app1), + ok = xref_base:delete(S8), + ok = file:delete(Xbeam), + ok = file:delete(Ybeam), + case os:type() of + {unix, _} -> + ok = file:del_dir(UDir), + ok = file:delete(UFile); + _ -> + true + end, ok. -default(suite) -> []; -default(doc) -> ["Default values of options"]; +%% Default values of options default(Conf) when is_list(Conf) -> S = new(), - ?line {error, _, {invalid_options,[not_an_option]}} = - xref_base:set_default(S, not_an_option, true), - ?line {error, _, {invalid_options,[{builtins, not_a_value}]}} = - xref_base:set_default(S, builtins, not_a_value), - ?line {error, _, {invalid_options,[not_an_option]}} = - xref_base:get_default(S, not_an_option), - ?line {error, _, {invalid_options,[not_an_option]}} = - xref_base:set_default(S, [not_an_option]), - - ?line D = xref_base:get_default(S), - ?line [{builtins,false},{recurse,false},{verbose,false},{warnings,true}] = - D, - - ?line ok = xref_base:delete(S), + {error, _, {invalid_options,[not_an_option]}} = + xref_base:set_default(S, not_an_option, true), + {error, _, {invalid_options,[{builtins, not_a_value}]}} = + xref_base:set_default(S, builtins, not_a_value), + {error, _, {invalid_options,[not_an_option]}} = + xref_base:get_default(S, not_an_option), + {error, _, {invalid_options,[not_an_option]}} = + xref_base:set_default(S, [not_an_option]), + + D = xref_base:get_default(S), + [{builtins,false},{recurse,false},{verbose,false},{warnings,true}] = + D, + + ok = xref_base:delete(S), ok. -info(suite) -> []; -info(doc) -> ["The info functions"]; +%% The info functions info(Conf) when is_list(Conf) -> CopyDir = ?copydir, Dir = fname(CopyDir,"rel2"), @@ -849,197 +812,195 @@ info(Conf) when is_list(Conf) -> Xbeam = fname(EB2, "x.beam"), Ybeam = fname(EB1_1, "y.beam"), - ?line {ok, x} = compile:file(X, [debug_info, {outdir,EB2}]), - ?line {ok, y} = compile:file(Y, [debug_info, {outdir,EB1_1}]), - - ?line {ok, _} = start(s), - ?line {error, _, {no_such_info, release}} = xref:info(s, release), - ?line {error, _, {no_such_info, release}} = xref:info(s, release, rel), - ?line {error, _, {no_such_module, mod}} = xref:info(s, modules, mod), - ?line {error, _, {no_such_application, app}} = - xref:info(s, applications, app), - ?line {error, _, {no_such_release, rel}} = xref:info(s, releases, rel), - ?line ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), - ?line {ok, rel2} = xref:add_release(s, Dir), - ?line 9 = length(xref:info(s)), - ?line [{x,_}, {y, _}] = xref:info(s, modules), - ?line [{app1,_}, {app2, _}] = xref:info(s, applications), - ?line [{rel2,_}] = xref:info(s, releases), - ?line [] = xref:info(s, libraries), - ?line [{x,_}] = xref:info(s, modules, x), - ?line [{rel2,_}] = xref:info(s, releases, rel2), - ?line {error, _, {no_such_library, foo}} = xref:info(s, libraries, [foo]), - - ?line {ok, lib1} = - compile:file(fname(LDir,lib1),[debug_info,{outdir,LDir}]), - ?line {ok, lib2} = - compile:file(fname(LDir,lib2),[debug_info,{outdir,LDir}]), - ?line ok = xref:set_library_path(s, [LDir], [{verbose,false}]), - ?line [{lib1,_}, {lib2, _}] = xref:info(s, libraries), - ?line [{lib1,_}, {lib2, _}] = xref:info(s, libraries, [lib1,lib2]), - ?line ok = file:delete(fname(LDir, "lib1.beam")), - ?line ok = file:delete(fname(LDir, "lib2.beam")), - - ?line check_state(s), - - ?line xref:stop(s), - - ?line ok = file:delete(Xbeam), - ?line ok = file:delete(Ybeam), + {ok, x} = compile:file(X, [debug_info, {outdir,EB2}]), + {ok, y} = compile:file(Y, [debug_info, {outdir,EB1_1}]), + + {ok, _} = start(s), + {error, _, {no_such_info, release}} = xref:info(s, release), + {error, _, {no_such_info, release}} = xref:info(s, release, rel), + {error, _, {no_such_module, mod}} = xref:info(s, modules, mod), + {error, _, {no_such_application, app}} = + xref:info(s, applications, app), + {error, _, {no_such_release, rel}} = xref:info(s, releases, rel), + ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), + {ok, rel2} = xref:add_release(s, Dir), + 9 = length(xref:info(s)), + [{x,_}, {y, _}] = xref:info(s, modules), + [{app1,_}, {app2, _}] = xref:info(s, applications), + [{rel2,_}] = xref:info(s, releases), + [] = xref:info(s, libraries), + [{x,_}] = xref:info(s, modules, x), + [{rel2,_}] = xref:info(s, releases, rel2), + {error, _, {no_such_library, foo}} = xref:info(s, libraries, [foo]), + + {ok, lib1} = + compile:file(fname(LDir,lib1),[debug_info,{outdir,LDir}]), + {ok, lib2} = + compile:file(fname(LDir,lib2),[debug_info,{outdir,LDir}]), + ok = xref:set_library_path(s, [LDir], [{verbose,false}]), + [{lib1,_}, {lib2, _}] = xref:info(s, libraries), + [{lib1,_}, {lib2, _}] = xref:info(s, libraries, [lib1,lib2]), + ok = file:delete(fname(LDir, "lib1.beam")), + ok = file:delete(fname(LDir, "lib2.beam")), + + check_state(s), + + xref:stop(s), + + ok = file:delete(Xbeam), + ok = file:delete(Ybeam), ok. -lib(suite) -> []; -lib(doc) -> ["Library modules"]; +%% Library modules lib(Conf) when is_list(Conf) -> CopyDir = ?copydir, Dir = fname(CopyDir,"lib_test"), UDir = fname([CopyDir,"dir","non_existent"]), - ?line {ok, lib1} = compile:file(fname(Dir,lib1),[debug_info,{outdir,Dir}]), - ?line {ok, lib2} = compile:file(fname(Dir,lib2),[debug_info,{outdir,Dir}]), - ?line {ok, lib3} = compile:file(fname(Dir,lib3),[debug_info,{outdir,Dir}]), - ?line {ok, t} = compile:file(fname(Dir,t),[debug_info,{outdir,Dir}]), - - ?line {ok, _} = start(s), - ?line ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), - ?line {ok, t} = xref:add_module(s, fname(Dir,"t.beam")), - ?line {error, _, {invalid_options,[not_an_option]}} = - xref:set_library_path(s, ["foo"], [not_an_option]), - ?line {error, _, {invalid_path,otp}} = xref:set_library_path(s,otp), - ?line {error, _, {invalid_path,[""]}} = xref:set_library_path(s,[""]), - ?line {error, _, {invalid_path,[[$a | $b]]}} = - xref:set_library_path(s,[[$a | $b]]), - ?line {error, _, {invalid_path,[otp]}} = xref:set_library_path(s,[otp]), - ?line {ok, []} = xref:get_library_path(s), - ?line ok = xref:set_library_path(s, [Dir], [{verbose,false}]), - ?line {ok, UnknownFunctions} = xref:q(s, "U"), - ?line [{lib1,unknown,0}, {lib2,local,0}, - {lib2,unknown,0}, {unknown,unknown,0}] - = UnknownFunctions, - ?line {ok, [{lib2,f,0},{lib3,f,0}]} = xref:q(s, "DF"), - ?line {ok, []} = xref:q(s, "DF_1"), - ?line {ok, [{lib2,f,0}]} = xref:q(s, "DF_2"), - ?line {ok, [{lib2,f,0}]} = xref:q(s, "DF_3"), - - ?line {ok, [unknown]} = xref:q(s, "UM"), - ?line {ok, UnknownDefAt} = xref:q(s, "(Lin)U"), - ?line [{{lib1,unknown,0},0},{{lib2,local,0},0}, {{lib2,unknown,0},0}, - {{unknown,unknown,0},0}] = UnknownDefAt, - ?line {ok, LibFuns} = xref:q(s, "X * LM"), - ?line [{lib2,f,0},{lib3,f,0}] = LibFuns, - ?line {ok, LibMods} = xref:q(s, "LM"), - ?line [lib1,lib2,lib3] = LibMods, - ?line {ok, [{{lib2,f,0},0},{{lib3,f,0},0}]} = xref:q(s, "(Lin) (LM * X)"), - ?line {ok, [{{lib1,unknown,0},0}, {{lib2,f,0},0}, {{lib2,local,0},0}, - {{lib2,unknown,0},0}, {{lib3,f,0},0}]} = xref:q(s,"(Lin)LM"), - ?line {ok,[lib1,lib2,lib3,t,unknown]} = xref:q(s,"M"), - ?line {ok,[{lib2,f,0},{lib3,f,0},{t,t,0}]} = xref:q(s,"X * M"), - ?line check_state(s), - - ?line copy_file(fname(Dir, "lib1.erl"), fname(Dir,"lib1.beam")), - ?line ok = xref:set_library_path(s, [Dir]), - ?line {error, _, _} = xref:q(s, "U"), + {ok, lib1} = compile:file(fname(Dir,lib1),[debug_info,{outdir,Dir}]), + {ok, lib2} = compile:file(fname(Dir,lib2),[debug_info,{outdir,Dir}]), + {ok, lib3} = compile:file(fname(Dir,lib3),[debug_info,{outdir,Dir}]), + {ok, t} = compile:file(fname(Dir,t),[debug_info,{outdir,Dir}]), + + {ok, _} = start(s), + ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), + {ok, t} = xref:add_module(s, fname(Dir,"t.beam")), + {error, _, {invalid_options,[not_an_option]}} = + xref:set_library_path(s, ["foo"], [not_an_option]), + {error, _, {invalid_path,otp}} = xref:set_library_path(s,otp), + {error, _, {invalid_path,[""]}} = xref:set_library_path(s,[""]), + {error, _, {invalid_path,[[$a | $b]]}} = + xref:set_library_path(s,[[$a | $b]]), + {error, _, {invalid_path,[otp]}} = xref:set_library_path(s,[otp]), + {ok, []} = xref:get_library_path(s), + ok = xref:set_library_path(s, [Dir], [{verbose,false}]), + {ok, UnknownFunctions} = xref:q(s, "U"), + [{lib1,unknown,0}, {lib2,local,0}, + {lib2,unknown,0}, {unknown,unknown,0}] + = UnknownFunctions, + {ok, [{lib2,f,0},{lib3,f,0}]} = xref:q(s, "DF"), + {ok, []} = xref:q(s, "DF_1"), + {ok, [{lib2,f,0}]} = xref:q(s, "DF_2"), + {ok, [{lib2,f,0}]} = xref:q(s, "DF_3"), + + {ok, [unknown]} = xref:q(s, "UM"), + {ok, UnknownDefAt} = xref:q(s, "(Lin)U"), + [{{lib1,unknown,0},0},{{lib2,local,0},0}, {{lib2,unknown,0},0}, + {{unknown,unknown,0},0}] = UnknownDefAt, + {ok, LibFuns} = xref:q(s, "X * LM"), + [{lib2,f,0},{lib3,f,0}] = LibFuns, + {ok, LibMods} = xref:q(s, "LM"), + [lib1,lib2,lib3] = LibMods, + {ok, [{{lib2,f,0},0},{{lib3,f,0},0}]} = xref:q(s, "(Lin) (LM * X)"), + {ok, [{{lib1,unknown,0},0}, {{lib2,f,0},0}, {{lib2,local,0},0}, + {{lib2,unknown,0},0}, {{lib3,f,0},0}]} = xref:q(s,"(Lin)LM"), + {ok,[lib1,lib2,lib3,t,unknown]} = xref:q(s,"M"), + {ok,[{lib2,f,0},{lib3,f,0},{t,t,0}]} = xref:q(s,"X * M"), + check_state(s), + + copy_file(fname(Dir, "lib1.erl"), fname(Dir,"lib1.beam")), + ok = xref:set_library_path(s, [Dir]), + {error, _, _} = xref:q(s, "U"), %% OTP-3921. AM and LM not always disjoint. - ?line {ok, lib1} = compile:file(fname(Dir,lib1),[debug_info,{outdir,Dir}]), - ?line {ok, lib1} = xref:add_module(s, fname(Dir,"lib1.beam")), - ?line check_state(s), - - ?line {error, _, {file_error, _, _}} = xref:set_library_path(s, [UDir]), - - ?line xref:stop(s), - ?line ok = file:delete(fname(Dir, "lib1.beam")), - ?line ok = file:delete(fname(Dir, "lib2.beam")), - ?line ok = file:delete(fname(Dir, "lib3.beam")), - ?line ok = file:delete(fname(Dir, "t.beam")), - - ?line {ok, cp} = compile:file(fname(Dir,cp),[debug_info,{outdir,Dir}]), - ?line {ok, _} = start(s), - ?line ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), - ?line {ok, cp} = xref:add_module(s, fname(Dir,"cp.beam")), - ?line {ok, [{lists, sort, 1}]} = xref:q(s, "U"), - ?line ok = xref:set_library_path(s, code_path), - ?line {ok, []} = xref:q(s, "U"), - ?line check_state(s), - ?line xref:stop(s), - ?line ok = file:delete(fname(Dir, "cp.beam")), + {ok, lib1} = compile:file(fname(Dir,lib1),[debug_info,{outdir,Dir}]), + {ok, lib1} = xref:add_module(s, fname(Dir,"lib1.beam")), + check_state(s), + + {error, _, {file_error, _, _}} = xref:set_library_path(s, [UDir]), + + xref:stop(s), + ok = file:delete(fname(Dir, "lib1.beam")), + ok = file:delete(fname(Dir, "lib2.beam")), + ok = file:delete(fname(Dir, "lib3.beam")), + ok = file:delete(fname(Dir, "t.beam")), + + {ok, cp} = compile:file(fname(Dir,cp),[debug_info,{outdir,Dir}]), + {ok, _} = start(s), + ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), + {ok, cp} = xref:add_module(s, fname(Dir,"cp.beam")), + {ok, [{lists, sort, 1}]} = xref:q(s, "U"), + ok = xref:set_library_path(s, code_path), + {ok, []} = xref:q(s, "U"), + check_state(s), + xref:stop(s), + ok = file:delete(fname(Dir, "cp.beam")), ok. -read(suite) -> []; -read(doc) -> ["Data read from the Abstract Code"]; +%% Data read from the Abstract Code read(Conf) when is_list(Conf) -> CopyDir = ?copydir, Dir = fname(CopyDir,"read"), File = fname(Dir, "read"), Beam = fname(Dir, "read.beam"), - ?line {ok, read} = compile:file(File, [debug_info,{outdir,Dir}]), - ?line do_read(File, abstract_v2), - ?line copy_file(fname(Dir, "read.beam.v1"), Beam), - ?line do_read(File, abstract_v1), - ?line ok = file:delete(Beam), + {ok, read} = compile:file(File, [debug_info,{outdir,Dir}]), + do_read(File, abstract_v2), + copy_file(fname(Dir, "read.beam.v1"), Beam), + do_read(File, abstract_v1), + ok = file:delete(Beam), ok. do_read(File, Version) -> - ?line {ok, _} = start(s), - ?line ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), - ?line {ok, read} = xref:add_module(s, File), + {ok, _} = start(s), + ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), + {ok, read} = xref:add_module(s, File), - ?line {U, OK, OKB} = read_expected(Version), + {U, OK, OKB} = read_expected(Version), %% {ok, UC} = xref:q(s, "(Lin) UC"), %% RR = to_external(converse(family_to_relation(family(UC)))), %% lists:foreach(fun(X) -> io:format("~w~n", [X]) end, RR), Unres = to_external(relation_to_family(converse(from_term(U)))), - ?line {ok, Unres} = xref:q(s, "(Lin) UC"), + {ok, Unres} = xref:q(s, "(Lin) UC"), %% {ok, EE} = xref:q(s, "(Lin) (E - UC)"), %% AA = to_external(converse(family_to_relation(family(EE)))), %% lists:foreach(fun(X) -> io:format("~w~n", [X]) end, AA), Calls = to_external(relation_to_family(converse(from_term(OK)))), - ?line {ok, Calls} = xref:q(s, "(Lin) (E - UC) "), - - ?line ok = check_state(s), - ?line {ok, UM} = xref:q(s, "UM"), - ?line true = member('$M_EXPR', UM), - - ?line {ok, X} = xref:q(s, "X"), - ?line true = member({read, module_info, 0}, X), - ?line false = member({foo, module_info, 0}, X), - ?line false = member({erlang, module_info, 0}, X), - ?line {ok, Unknowns} = xref:q(s, "U"), - ?line false = member({read, module_info, 0}, Unknowns), - ?line true = member({foo, module_info, 0}, Unknowns), - ?line true = member({erlang, module_info, 0}, Unknowns), - ?line {ok, LC} = xref:q(s, "LC"), - ?line true = member({{read,bi,0},{read,bi,0}}, LC), - - ?line ok = xref:set_library_path(s, add_erts_code_path(fname(code:lib_dir(kernel),ebin))), - ?line io:format("~p~n",[(catch xref:get_library_path(s))]), - ?line {ok, X2} = xref:q(s, "X"), - ?line ok = check_state(s), - ?line true = member({read, module_info, 0}, X2), - ?line false = member({foo, module_info, 0}, X2), - ?line true = member({erlang, module_info, 0}, X2), - ?line {ok, Unknowns2} = xref:q(s, "U"), - ?line false = member({read, module_info, 0}, Unknowns2), - ?line true = member({foo, module_info, 0}, Unknowns2), - ?line false = member({erlang, module_info, 0}, Unknowns2), - - ?line ok = xref:remove_module(s, read), - ?line {ok, read} = xref:add_module(s, File, [{builtins,true}]), + {ok, Calls} = xref:q(s, "(Lin) (E - UC) "), + + ok = check_state(s), + {ok, UM} = xref:q(s, "UM"), + true = member('$M_EXPR', UM), + + {ok, X} = xref:q(s, "X"), + true = member({read, module_info, 0}, X), + false = member({foo, module_info, 0}, X), + false = member({erlang, module_info, 0}, X), + {ok, Unknowns} = xref:q(s, "U"), + false = member({read, module_info, 0}, Unknowns), + true = member({foo, module_info, 0}, Unknowns), + true = member({erlang, module_info, 0}, Unknowns), + {ok, LC} = xref:q(s, "LC"), + true = member({{read,bi,0},{read,bi,0}}, LC), + + ok = xref:set_library_path(s, add_erts_code_path(fname(code:lib_dir(kernel),ebin))), + io:format("~p~n",[(catch xref:get_library_path(s))]), + {ok, X2} = xref:q(s, "X"), + ok = check_state(s), + true = member({read, module_info, 0}, X2), + false = member({foo, module_info, 0}, X2), + true = member({erlang, module_info, 0}, X2), + {ok, Unknowns2} = xref:q(s, "U"), + false = member({read, module_info, 0}, Unknowns2), + true = member({foo, module_info, 0}, Unknowns2), + false = member({erlang, module_info, 0}, Unknowns2), + + ok = xref:remove_module(s, read), + {ok, read} = xref:add_module(s, File, [{builtins,true}]), UnresB = to_external(relation_to_family(converse(from_term(U)))), - ?line {ok, UnresB} = xref:q(s, "(Lin) UC"), + {ok, UnresB} = xref:q(s, "(Lin) UC"), CallsB = to_external(relation_to_family(converse(from_term(OKB)))), - ?line {ok, CallsB} = xref:q(s, "(Lin) (E - UC) "), - ?line ok = check_state(s), - ?line {ok, XU} = xref:q(s, "XU"), - ?line Erl = set([{erlang,length,1},{erlang,integer,1}, - {erlang,binary_to_term,1}]), - ?line [{erlang,binary_to_term,1},{erlang,length,1}] = - to_external(intersection(set(XU), Erl)), - ?line xref:stop(s). + {ok, CallsB} = xref:q(s, "(Lin) (E - UC) "), + ok = check_state(s), + {ok, XU} = xref:q(s, "XU"), + Erl = set([{erlang,length,1},{erlang,integer,1}, + {erlang,binary_to_term,1}]), + [{erlang,binary_to_term,1},{erlang,length,1}] = + to_external(intersection(set(XU), Erl)), + xref:stop(s). %% What is expected when xref_SUITE_data/read/read.erl is added: read_expected(Version) -> @@ -1051,174 +1012,172 @@ read_expected(Version) -> FF = {read,funfuns,0}, U = [{POS1+5,{FF,{dist,'$F_EXPR',0}}}, - {POS1+8,{FF,{dist,'$F_EXPR',0}}}, - {POS2+8,{{read,funfuns,0},{expr,'$F_EXPR',1}}}, - {POS3+4,{FF,{expr,'$F_EXPR',2}}}, - {POS4+2,{FF,{modul,'$F_EXPR',1}}}, - {POS4+4,{FF,{spm,'$F_EXPR',1}}}, - {POS4+6,{FF,{spm,'$F_EXPR',1}}}, - {POS4+8,{FF,{spm,'$F_EXPR',1}}}, - {POS5+1,{FF,{'$M_EXPR','$F_EXPR',0}}}, - {POS5+2,{FF,{'$M_EXPR','$F_EXPR',0}}}, - {POS5+3,{FF,{'$M_EXPR','$F_EXPR',0}}}, - {POS6+1,{FF,{'$M_EXPR','$F_EXPR',0}}}, - {POS6+2,{FF,{'$M_EXPR','$F_EXPR',0}}}, - {POS6+4,{FF,{n,'$F_EXPR',-1}}}, - {POS7+1,{FF,{'$M_EXPR',f,1}}}, - {POS7+2,{FF,{'$M_EXPR',f,1}}}, - {POS8+2,{FF,{hej,'$F_EXPR',1}}}, - {POS8+3,{FF,{t,'$F_EXPR',1}}}, - {POS8+5,{FF,{a,'$F_EXPR',1}}}, - {POS8+7,{FF,{m,'$F_EXPR',1}}}, - {POS9+1,{FF,{'$M_EXPR',f,1}}}, - {POS9+3,{FF,{a,'$F_EXPR',1}}}, - {POS10+1,{FF,{'$M_EXPR',foo,1}}}, - {POS10+2,{FF,{'$M_EXPR','$F_EXPR',1}}}, - {POS10+3,{FF,{'$M_EXPR','$F_EXPR',2}}}, - {POS10+4,{FF,{'$M_EXPR','$F_EXPR',1}}}, - {POS10+5,{FF,{'$M_EXPR',san,1}}}, - {POS10+6,{FF,{'$M_EXPR','$F_EXPR',1}}}, - {POS11+1,{FF,{'$M_EXPR','$F_EXPR',1}}}, - {POS11+2,{FF,{'$M_EXPR','$F_EXPR',-1}}}, - {POS11+3,{FF,{m,f,-1}}}, - {POS11+4,{FF,{m,f,-1}}}, - {POS11+5,{FF,{'$M_EXPR','$F_EXPR',1}}}, - {POS11+6,{FF,{'$M_EXPR','$F_EXPR',1}}}, - {POS12+1,{FF,{'$M_EXPR','$F_EXPR',-1}}}, - {POS12+4,{FF,{'$M_EXPR','$F_EXPR',2}}}, - {POS12+7,{FF,{'$M_EXPR','$F_EXPR',-1}}}, - {POS12+8,{FF,{m4,f4,-1}}}, - {POS13+2,{FF,{debug,'$F_EXPR',0}}}, - {POS13+3,{FF,{'$M_EXPR','$F_EXPR',-1}}}, - {POS14+8,{{read,bi,0},{'$M_EXPR','$F_EXPR',1}}}], + {POS1+8,{FF,{dist,'$F_EXPR',0}}}, + {POS2+8,{{read,funfuns,0},{expr,'$F_EXPR',1}}}, + {POS3+4,{FF,{expr,'$F_EXPR',2}}}, + {POS4+2,{FF,{modul,'$F_EXPR',1}}}, + {POS4+4,{FF,{spm,'$F_EXPR',1}}}, + {POS4+6,{FF,{spm,'$F_EXPR',1}}}, + {POS4+8,{FF,{spm,'$F_EXPR',1}}}, + {POS5+1,{FF,{'$M_EXPR','$F_EXPR',0}}}, + {POS5+2,{FF,{'$M_EXPR','$F_EXPR',0}}}, + {POS5+3,{FF,{'$M_EXPR','$F_EXPR',0}}}, + {POS6+1,{FF,{'$M_EXPR','$F_EXPR',0}}}, + {POS6+2,{FF,{'$M_EXPR','$F_EXPR',0}}}, + {POS6+4,{FF,{n,'$F_EXPR',-1}}}, + {POS7+1,{FF,{'$M_EXPR',f,1}}}, + {POS7+2,{FF,{'$M_EXPR',f,1}}}, + {POS8+2,{FF,{hej,'$F_EXPR',1}}}, + {POS8+3,{FF,{t,'$F_EXPR',1}}}, + {POS8+5,{FF,{a,'$F_EXPR',1}}}, + {POS8+7,{FF,{m,'$F_EXPR',1}}}, + {POS9+1,{FF,{'$M_EXPR',f,1}}}, + {POS9+3,{FF,{a,'$F_EXPR',1}}}, + {POS10+1,{FF,{'$M_EXPR',foo,1}}}, + {POS10+2,{FF,{'$M_EXPR','$F_EXPR',1}}}, + {POS10+3,{FF,{'$M_EXPR','$F_EXPR',2}}}, + {POS10+4,{FF,{'$M_EXPR','$F_EXPR',1}}}, + {POS10+5,{FF,{'$M_EXPR',san,1}}}, + {POS10+6,{FF,{'$M_EXPR','$F_EXPR',1}}}, + {POS11+1,{FF,{'$M_EXPR','$F_EXPR',1}}}, + {POS11+2,{FF,{'$M_EXPR','$F_EXPR',-1}}}, + {POS11+3,{FF,{m,f,-1}}}, + {POS11+4,{FF,{m,f,-1}}}, + {POS11+5,{FF,{'$M_EXPR','$F_EXPR',1}}}, + {POS11+6,{FF,{'$M_EXPR','$F_EXPR',1}}}, + {POS12+1,{FF,{'$M_EXPR','$F_EXPR',-1}}}, + {POS12+4,{FF,{'$M_EXPR','$F_EXPR',2}}}, + {POS12+7,{FF,{'$M_EXPR','$F_EXPR',-1}}}, + {POS12+8,{FF,{m4,f4,-1}}}, + {POS13+2,{FF,{debug,'$F_EXPR',0}}}, + {POS13+3,{FF,{'$M_EXPR','$F_EXPR',-1}}}, + {POS14+8,{{read,bi,0},{'$M_EXPR','$F_EXPR',1}}}], O1 = [{20,{{read,lc,0},{ets,new,0}}}, - {21,{{read,lc,0},{ets,tab2list,1}}}, - {POS1+1,{FF,{erlang,spawn,1}}}, - {POS1+1,{FF,{mod17,fun17,0}}}, - {POS1+2,{FF,{erlang,spawn,1}}}, - {POS1+2,{FF,{read,local,0}}}, - {POS1+3,{FF,{erlang,spawn,1}}}, - {POS1+4,{FF,{dist,func,0}}}, - {POS1+4,{FF,{erlang,spawn,1}}}, - {POS1+5,{FF,{erlang,spawn,1}}}, - {POS1+6,{FF,{erlang,spawn_link,1}}}, - {POS1+6,{FF,{mod17,fun17,0}}}, - {POS1+7,{FF,{dist,func,0}}}, - {POS1+7,{FF,{erlang,spawn_link,1}}}, - {POS1+8,{FF,{erlang,spawn_link,1}}}, - {POS2+1,{FF,{d,f,0}}}, - {POS2+1,{FF,{dist,func,2}}}, - {POS2+1,{FF,{erlang,spawn,2}}}, - {POS2+2,{FF,{dist,func,2}}}, - {POS2+2,{FF,{erlang,spawn,2}}}, - {POS2+2,{FF,{mod42,func,0}}}, - {POS2+3,{FF,{d,f,0}}}, - {POS2+3,{FF,{dist,func,2}}}, - {POS2+3,{FF,{erlang,spawn_link,2}}}, - {POS2+4,{FF,{dist,func,2}}}, - {POS2+4,{FF,{erlang,spawn_link,2}}}, - {POS2+4,{FF,{mod42,func,0}}}, - {POS3+1,{FF,{dist,func,2}}}, - {POS3+3,{FF,{dist,func,2}}}, - {POS4+1,{FF,{erlang,spawn,4}}}, - {POS4+1,{FF,{modul,function,0}}}, - {POS4+2,{FF,{erlang,spawn,4}}}, - {POS4+3,{FF,{dist,func,2}}}, - {POS4+3,{FF,{erlang,spawn,4}}}, - {POS4+3,{FF,{spm,spf,2}}}, - {POS4+4,{FF,{dist,func,2}}}, - {POS4+4,{FF,{erlang,spawn,4}}}, - {POS4+5,{FF,{dist,func,2}}}, - {POS4+5,{FF,{erlang,spawn_link,4}}}, - {POS4+5,{FF,{spm,spf,2}}}, - {POS4+6,{FF,{dist,func,2}}}, - {POS4+6,{FF,{erlang,spawn_link,4}}}, - {POS4+7,{FF,{erlang,spawn_opt,4}}}, - {POS4+7,{FF,{read,bi,0}}}, - {POS4+7,{FF,{spm,spf,2}}}, - {POS4+8,{FF,{erlang,spawn_opt,4}}}, - {POS4+8,{FF,{read,bi,0}}}, - {POS5+1,{FF,{erlang,spawn,1}}}, - {POS5+2,{FF,{erlang,spawn,1}}}, - {POS5+3,{FF,{erlang,spawn_link,1}}}, - {POS6+1,{FF,{erlang,spawn,2}}}, - {POS6+2,{FF,{erlang,spawn_link,2}}}, - {POS7+1,{FF,{erlang,spawn,4}}}, - {POS7+2,{FF,{erlang,spawn_opt,4}}}, - {POS8+1,{FF,{hej,san,1}}}, - {POS8+4,{FF,{a,b,1}}}, - {POS8+4,{FF,{erlang,apply,2}}}, - {POS8+5,{FF,{erlang,apply,2}}}, - {POS8+6,{FF,{erlang,apply,3}}}, - {POS8+6,{FF,{m,f,1}}}, - {POS8+7,{FF,{erlang,apply,3}}}, - {POS9+1,{FF,{erlang,apply,3}}}, - {POS9+1,{FF,{read,bi,0}}}, - {POS9+2,{FF,{a,b,1}}}, - {POS9+2,{FF,{erlang,apply,2}}}, - {POS9+3,{FF,{erlang,apply,2}}}, - {POS9+4,{FF,{erlang,apply,2}}}, - {POS9+4,{FF,{erlang,not_a_function,1}}}, - {POS9+5,{FF,{erlang,apply,3}}}, - {POS9+5,{FF,{mod,func,2}}}, - {POS9+6,{FF,{erlang,apply,1}}}, - {POS9+7,{FF,{erlang,apply,2}}}, - {POS9+7,{FF,{math,add3,1}}}, - {POS9+8,{FF,{q,f,1}}}, - {POS10+4,{FF,{erlang,apply,2}}}, - {POS10+5,{FF,{mod1,fun1,1}}}, - {POS11+1,{FF,{erlang,apply,3}}}, - {POS11+2,{FF,{erlang,apply,3}}}, - {POS11+3,{FF,{erlang,apply,3}}}, - {POS11+4,{FF,{erlang,apply,3}}}, - {POS11+6,{FF,{erlang,apply,2}}}, - {POS12+1,{FF,{erlang,apply,2}}}, - {POS12+4,{FF,{erlang,apply,2}}}, - {POS12+5,{FF,{erlang,apply,3}}}, - {POS12+5,{FF,{m3,f3,2}}}, - {POS12+7,{FF,{erlang,apply,2}}}, - {POS12+8,{FF,{erlang,apply,3}}}, - {POS13+1,{FF,{dm,df,1}}}, - {POS13+6,{{read,bi,0},{foo,module_info,0}}}, - {POS13+7,{{read,bi,0},{read,module_info,0}}}, - {POS13+9,{{read,bi,0},{t,foo,1}}}, - {POS14+11,{{read,bi,0},{erlang,module_info,0}}}, - {POS14+17,{{read,bi,0},{read,bi,0}}}], + {21,{{read,lc,0},{ets,tab2list,1}}}, + {POS1+1,{FF,{erlang,spawn,1}}}, + {POS1+1,{FF,{mod17,fun17,0}}}, + {POS1+2,{FF,{erlang,spawn,1}}}, + {POS1+2,{FF,{read,local,0}}}, + {POS1+3,{FF,{erlang,spawn,1}}}, + {POS1+4,{FF,{dist,func,0}}}, + {POS1+4,{FF,{erlang,spawn,1}}}, + {POS1+5,{FF,{erlang,spawn,1}}}, + {POS1+6,{FF,{erlang,spawn_link,1}}}, + {POS1+6,{FF,{mod17,fun17,0}}}, + {POS1+7,{FF,{dist,func,0}}}, + {POS1+7,{FF,{erlang,spawn_link,1}}}, + {POS1+8,{FF,{erlang,spawn_link,1}}}, + {POS2+1,{FF,{d,f,0}}}, + {POS2+1,{FF,{dist,func,2}}}, + {POS2+1,{FF,{erlang,spawn,2}}}, + {POS2+2,{FF,{dist,func,2}}}, + {POS2+2,{FF,{erlang,spawn,2}}}, + {POS2+2,{FF,{mod42,func,0}}}, + {POS2+3,{FF,{d,f,0}}}, + {POS2+3,{FF,{dist,func,2}}}, + {POS2+3,{FF,{erlang,spawn_link,2}}}, + {POS2+4,{FF,{dist,func,2}}}, + {POS2+4,{FF,{erlang,spawn_link,2}}}, + {POS2+4,{FF,{mod42,func,0}}}, + {POS3+1,{FF,{dist,func,2}}}, + {POS3+3,{FF,{dist,func,2}}}, + {POS4+1,{FF,{erlang,spawn,4}}}, + {POS4+1,{FF,{modul,function,0}}}, + {POS4+2,{FF,{erlang,spawn,4}}}, + {POS4+3,{FF,{dist,func,2}}}, + {POS4+3,{FF,{erlang,spawn,4}}}, + {POS4+3,{FF,{spm,spf,2}}}, + {POS4+4,{FF,{dist,func,2}}}, + {POS4+4,{FF,{erlang,spawn,4}}}, + {POS4+5,{FF,{dist,func,2}}}, + {POS4+5,{FF,{erlang,spawn_link,4}}}, + {POS4+5,{FF,{spm,spf,2}}}, + {POS4+6,{FF,{dist,func,2}}}, + {POS4+6,{FF,{erlang,spawn_link,4}}}, + {POS4+7,{FF,{erlang,spawn_opt,4}}}, + {POS4+7,{FF,{read,bi,0}}}, + {POS4+7,{FF,{spm,spf,2}}}, + {POS4+8,{FF,{erlang,spawn_opt,4}}}, + {POS4+8,{FF,{read,bi,0}}}, + {POS5+1,{FF,{erlang,spawn,1}}}, + {POS5+2,{FF,{erlang,spawn,1}}}, + {POS5+3,{FF,{erlang,spawn_link,1}}}, + {POS6+1,{FF,{erlang,spawn,2}}}, + {POS6+2,{FF,{erlang,spawn_link,2}}}, + {POS7+1,{FF,{erlang,spawn,4}}}, + {POS7+2,{FF,{erlang,spawn_opt,4}}}, + {POS8+1,{FF,{hej,san,1}}}, + {POS8+4,{FF,{a,b,1}}}, + {POS8+4,{FF,{erlang,apply,2}}}, + {POS8+5,{FF,{erlang,apply,2}}}, + {POS8+6,{FF,{m,f,1}}}, + {POS9+1,{FF,{read,bi,0}}}, + {POS9+2,{FF,{a,b,1}}}, + {POS9+2,{FF,{erlang,apply,2}}}, + {POS9+3,{FF,{erlang,apply,2}}}, + {POS9+4,{FF,{erlang,apply,2}}}, + {POS9+4,{FF,{erlang,not_a_function,1}}}, + {POS9+5,{FF,{mod,func,2}}}, + {POS9+6,{FF,{erlang,apply,1}}}, + {POS9+7,{FF,{erlang,apply,2}}}, + {POS9+7,{FF,{math,add3,1}}}, + {POS9+8,{FF,{q,f,1}}}, + {POS10+4,{FF,{erlang,apply,2}}}, + {POS10+5,{FF,{mod1,fun1,1}}}, + {POS11+6,{FF,{erlang,apply,2}}}, + {POS12+1,{FF,{erlang,apply,2}}}, + {POS12+4,{FF,{erlang,apply,2}}}, + {POS12+5,{FF,{m3,f3,2}}}, + {POS12+7,{FF,{erlang,apply,2}}}, + {POS13+1,{FF,{dm,df,1}}}, + {POS13+6,{{read,bi,0},{foo,module_info,0}}}, + {POS13+7,{{read,bi,0},{read,module_info,0}}}, + {POS13+9,{{read,bi,0},{t,foo,1}}}, + {POS14+11,{{read,bi,0},{erlang,module_info,0}}}, + {POS14+17,{{read,bi,0},{read,bi,0}}}], OK = case Version of - abstract_v1 -> - [{POS8+3, {FF,{erlang,apply,3}}}, - {POS10+1, {FF,{erlang,apply,3}}}, - {POS10+6, {FF,{erlang,apply,3}}}] - ++ + abstract_v1 -> [{0,{FF,{read,'$F_EXPR',178}}}, {0,{FF,{modul,'$F_EXPR',179}}}] ++ O1; - _ -> + _ -> [{16,{FF,{read,'$F_EXPR',178}}}, {17,{FF,{modul,'$F_EXPR',179}}}] ++ O1 - end, + end, %% When builtins =:= true: OKB1 = [{POS13+1,{FF,{erts_debug,apply,4}}}, {POS13+2,{FF,{erts_debug,apply,4}}}, {POS13+3,{FF,{erts_debug,apply,4}}}, - {POS1+3, {FF,{erlang,binary_to_term,1}}}, + {POS1+3, {FF,{erlang,binary_to_term,1}}}, {POS3+1, {FF,{erlang,spawn,3}}}, {POS3+2, {FF,{erlang,spawn,3}}}, {POS3+3, {FF,{erlang,spawn_link,3}}}, {POS3+4, {FF,{erlang,spawn_link,3}}}, {POS6+4, {FF,{erlang,spawn,3}}}, + {POS8+6,{FF,{erlang,apply,3}}}, + {POS8+7,{FF,{erlang,apply,3}}}, + {POS9+1,{FF,{erlang,apply,3}}}, + {POS9+5,{FF,{erlang,apply,3}}}, + {POS11+1,{FF,{erlang,apply,3}}}, + {POS11+2,{FF,{erlang,apply,3}}}, + {POS11+3,{FF,{erlang,apply,3}}}, + {POS11+4,{FF,{erlang,apply,3}}}, + {POS12+5,{FF,{erlang,apply,3}}}, + {POS12+8,{FF,{erlang,apply,3}}}, {POS13+5, {{read,bi,0},{erlang,length,1}}}, {POS14+3, {{read,bi,0},{erlang,length,1}}}], %% Operators (OTP-8647): OKB = case Version of abstract_v1 -> - []; + [{POS8+3, {FF,{erlang,apply,3}}}, + {POS10+1, {FF,{erlang,apply,3}}}, + {POS10+6, {FF,{erlang,apply,3}}}]; _ -> [{POS13+16, {{read,bi,0},{erlang,'!',2}}}, {POS13+16, {{read,bi,0},{erlang,'-',1}}}, @@ -1228,18 +1187,17 @@ read_expected(Version) -> {POS15+2, {{read,bi,0},{erlang,'*',2}}}, {POS15+8, {{read,bi,0},{erlang,'/',2}}}] end - ++ [{POS14+19, {{read,bi,0},{erlang,'+',2}}}, - {POS14+21, {{read,bi,0},{erlang,'+',2}}}, - {POS13+16, {{read,bi,0},{erlang,'==',2}}}, - {POS14+15, {{read,bi,0},{erlang,'==',2}}}, - {POS13+5, {{read,bi,0},{erlang,'>',2}}}, - {POS14+3, {{read,bi,0},{erlang,'>',2}}}] - ++ OKB1 ++ OK, + ++ [{POS14+19, {{read,bi,0},{erlang,'+',2}}}, + {POS14+21, {{read,bi,0},{erlang,'+',2}}}, + {POS13+16, {{read,bi,0},{erlang,'==',2}}}, + {POS14+15, {{read,bi,0},{erlang,'==',2}}}, + {POS13+5, {{read,bi,0},{erlang,'>',2}}}, + {POS14+3, {{read,bi,0},{erlang,'>',2}}}] + ++ OKB1 ++ OK, {U, OK, OKB}. -read2(suite) -> []; -read2(doc) -> ["Data read from the Abstract Code (cont)"]; +%% Data read from the Abstract Code (cont) read2(Conf) when is_list(Conf) -> %% Handles the spawn_opt versions added in R9 (OTP-4180). %% Expected augmentations: try/catch, cond. @@ -1249,40 +1207,40 @@ read2(Conf) when is_list(Conf) -> MFile = fname(Dir, "read2"), Beam = fname(Dir, "read2.beam"), Test = <<"-module(read2). - -compile(export_all). - - f() -> - spawn_opt({read2,f}, % POS2 - [f()]), - spawn_opt(fun() -> foo end, [link]), - spawn_opt(f(), - {read2,f}, [{min_heap_size,1000}]), - spawn_opt(f(), - fun() -> f() end, [flopp]), - spawn_opt(f(), - read2, f, [], []); - f() -> - %% Duplicated unresolved calls are ignored: - (f())(foo,bar),(f())(foo,bar). % POS1 + -compile(export_all). + + f() -> + spawn_opt({read2,f}, % POS2 + [f()]), + spawn_opt(fun() -> foo end, [link]), + spawn_opt(f(), + {read2,f}, [{min_heap_size,1000}]), + spawn_opt(f(), + fun() -> f() end, [flopp]), + spawn_opt(f(), + read2, f, [], []); + f() -> + %% Duplicated unresolved calls are ignored: + (f())(foo,bar),(f())(foo,bar). % POS1 ">>, - ?line ok = file:write_file(File, Test), - ?line {ok, read2} = compile:file(File, [debug_info,{outdir,Dir}]), + ok = file:write_file(File, Test), + {ok, read2} = compile:file(File, [debug_info,{outdir,Dir}]), - ?line {ok, _} = xref:start(s), - ?line {ok, read2} = xref:add_module(s, MFile), - ?line {U0, OK0} = read2_expected(), + {ok, _} = xref:start(s), + {ok, read2} = xref:add_module(s, MFile), + {U0, OK0} = read2_expected(), U = to_external(relation_to_family(converse(from_term(U0)))), OK = to_external(relation_to_family(converse(from_term(OK0)))), - ?line {ok, U2} = xref:q(s, "(Lin) UC"), - ?line {ok, OK2} = xref:q(s, "(Lin) (E - UC)"), - ?line true = U =:= U2, - ?line true = OK =:= OK2, - ?line ok = check_state(s), - ?line xref:stop(s), - - ?line ok = file:delete(File), - ?line ok = file:delete(Beam), + {ok, U2} = xref:q(s, "(Lin) UC"), + {ok, OK2} = xref:q(s, "(Lin) (E - UC)"), + true = U =:= U2, + true = OK =:= OK2, + ok = check_state(s), + xref:stop(s), + + ok = file:delete(File), + ok = file:delete(Beam), ok. @@ -1292,36 +1250,34 @@ read2_expected() -> FF = {read2,f,0}, U = [{POS1,{FF,{'$M_EXPR','$F_EXPR',2}}}], OK = [{POS2,{FF,{erlang,spawn_opt,2}}}, - {POS2,{FF,FF}}, - {POS2+1,{FF,FF}}, - {POS2+2,{FF,{erlang,spawn_opt,2}}}, - {POS2+3,{FF,{erlang,spawn_opt,3}}}, - {POS2+3,{FF,FF}}, - {POS2+3,{FF,FF}}, - {POS2+5,{FF,{erlang,spawn_opt,3}}}, - {POS2+5,{FF,FF}}, - {POS2+6,{FF,FF}}, - {POS2+7,{FF,{erlang,spawn_opt,5}}}, - {POS2+7,{FF,FF}}, - {POS2+7,{FF,FF}}, - {POS1,{FF,FF}}], + {POS2,{FF,FF}}, + {POS2+1,{FF,FF}}, + {POS2+2,{FF,{erlang,spawn_opt,2}}}, + {POS2+3,{FF,{erlang,spawn_opt,3}}}, + {POS2+3,{FF,FF}}, + {POS2+3,{FF,FF}}, + {POS2+5,{FF,{erlang,spawn_opt,3}}}, + {POS2+5,{FF,FF}}, + {POS2+6,{FF,FF}}, + {POS2+7,{FF,{erlang,spawn_opt,5}}}, + {POS2+7,{FF,FF}}, + {POS2+7,{FF,FF}}, + {POS1,{FF,FF}}], {U, OK}. -remove(suite) -> []; -remove(doc) -> ["Remove modules, applications, releases"]; +%% Remove modules, applications, releases remove(Conf) when is_list(Conf) -> S = new(), - ?line {error, _, {no_such_module, mod}} = - xref_base:remove_module(S, mod), - ?line {error, _, {no_such_application, app}} = - xref_base:remove_application(S, app), - ?line {error, _, {no_such_release, rel}} = - xref_base:remove_release(S, rel), - ?line ok = xref_base:delete(S), + {error, _, {no_such_module, mod}} = + xref_base:remove_module(S, mod), + {error, _, {no_such_application, app}} = + xref_base:remove_application(S, app), + {error, _, {no_such_release, rel}} = + xref_base:remove_release(S, rel), + ok = xref_base:delete(S), ok. -replace(suite) -> []; -replace(doc) -> ["Replace modules, applications, releases"]; +%% Replace modules, applications, releases replace(Conf) when is_list(Conf) -> CopyDir = ?copydir, Dir = fname(CopyDir,"rel2"), @@ -1335,105 +1291,103 @@ replace(Conf) when is_list(Conf) -> Xbeam = fname(EB1_1, "x.beam"), Ybeam = fname(EB1_1, "y.beam"), - ?line {ok, x} = compile:file(X, [debug_info, {outdir,EB1_0}]), - ?line {ok, x} = compile:file(X, [debug_info, {outdir,EB1_1}]), - ?line {ok, y} = compile:file(Y, [debug_info, {outdir,EB1_1}]), - - ?line {ok, _} = start(s), - ?line {ok, false} = xref:set_default(s, verbose, false), - ?line {ok, true} = xref:set_default(s, warnings, false), - ?line {ok, rel2} = xref:add_release(s, Dir, []), - ?line {error, _, _} = xref:replace_application(s, app1, "no_data"), - ?line {error, _, {no_such_application, app12}} = - xref:replace_application(s, app12, A1_0, []), - ?line {error, _, {invalid_filename,{foo,bar}}} = - xref:replace_application(s, app1, {foo,bar}, []), - ?line {error, _, {invalid_options,[not_an_option]}} = - xref:replace_application(s, foo, bar, [not_an_option]), - ?line {error, _, {invalid_options,[{builtins,not_a_value}]}} = - xref:replace_application(s, foo, bar, [{builtins,not_a_value}]), - ?line {ok, app1} = - xref:replace_application(s, app1, A1_0), - ?line [{_, AppInfo}] = xref:info(s, applications, app1), - ?line {value, {release, [rel2]}} = keysearch(release, 1, AppInfo), - - ?line {error, _, {no_such_module, xx}} = - xref:replace_module(s, xx, Xbeam, []), - ?line {error, _, {invalid_options,[{builtins,true},not_an_option]}} = - xref:replace_module(s, foo, bar,[{builtins,true},not_an_option]), - ?line {error, _, {invalid_options,[{builtins,not_a_value}]}} = - xref:replace_module(s, foo, bar, [{builtins,not_a_value}]), - ?line {error, _, {invalid_filename,{foo,bar}}} = - xref:replace_module(s, x, {foo,bar}), - ?line {ok, x} = xref:replace_module(s, x, Xbeam), - ?line [{x, ModInfo}] = xref:info(s, modules, x), - ?line {value, {application, [app1]}} = - keysearch(application, 1, ModInfo), - - ?line {ok, x} = compile:file(X, [no_debug_info, {outdir,EB1_1}]), - ?line {error, _, {no_debug_info, _}} = xref:replace_module(s, x, Xbeam), - ?line {error, _, {module_mismatch, x,y}} = - xref:replace_module(s, x, Ybeam), - ?line case os:type() of - {unix, _} -> - ?line hide_file(Ybeam), - ?line {error, _, {file_error, _, _}} = - xref:replace_module(s, x, Ybeam); - _ -> - true - end, - ?line ok = xref:remove_module(s, x), - ?line {error, _, {no_debug_info, _}} = xref:add_module(s, Xbeam), + {ok, x} = compile:file(X, [debug_info, {outdir,EB1_0}]), + {ok, x} = compile:file(X, [debug_info, {outdir,EB1_1}]), + {ok, y} = compile:file(Y, [debug_info, {outdir,EB1_1}]), + + {ok, _} = start(s), + {ok, false} = xref:set_default(s, verbose, false), + {ok, true} = xref:set_default(s, warnings, false), + {ok, rel2} = xref:add_release(s, Dir, []), + {error, _, _} = xref:replace_application(s, app1, "no_data"), + {error, _, {no_such_application, app12}} = + xref:replace_application(s, app12, A1_0, []), + {error, _, {invalid_filename,{foo,bar}}} = + xref:replace_application(s, app1, {foo,bar}, []), + {error, _, {invalid_options,[not_an_option]}} = + xref:replace_application(s, foo, bar, [not_an_option]), + {error, _, {invalid_options,[{builtins,not_a_value}]}} = + xref:replace_application(s, foo, bar, [{builtins,not_a_value}]), + {ok, app1} = + xref:replace_application(s, app1, A1_0), + [{_, AppInfo}] = xref:info(s, applications, app1), + {value, {release, [rel2]}} = keysearch(release, 1, AppInfo), + + {error, _, {no_such_module, xx}} = + xref:replace_module(s, xx, Xbeam, []), + {error, _, {invalid_options,[{builtins,true},not_an_option]}} = + xref:replace_module(s, foo, bar,[{builtins,true},not_an_option]), + {error, _, {invalid_options,[{builtins,not_a_value}]}} = + xref:replace_module(s, foo, bar, [{builtins,not_a_value}]), + {error, _, {invalid_filename,{foo,bar}}} = + xref:replace_module(s, x, {foo,bar}), + {ok, x} = xref:replace_module(s, x, Xbeam), + [{x, ModInfo}] = xref:info(s, modules, x), + {value, {application, [app1]}} = + keysearch(application, 1, ModInfo), + + {ok, x} = compile:file(X, [no_debug_info, {outdir,EB1_1}]), + {error, _, {no_debug_info, _}} = xref:replace_module(s, x, Xbeam), + {error, _, {module_mismatch, x,y}} = + xref:replace_module(s, x, Ybeam), + case os:type() of + {unix, _} -> + hide_file(Ybeam), + {error, _, {file_error, _, _}} = + xref:replace_module(s, x, Ybeam); + _ -> + true + end, + ok = xref:remove_module(s, x), + {error, _, {no_debug_info, _}} = xref:add_module(s, Xbeam), %% "app2" is ignored, the old application name is kept - ?line {ok, app1} = xref:replace_application(s, app1, A2), + {ok, app1} = xref:replace_application(s, app1, A2), - ?line xref:stop(s), - ?line ok = file:delete(fname(EB1_0, "x.beam")), - ?line ok = file:delete(Xbeam), - ?line ok = file:delete(Ybeam), + xref:stop(s), + ok = file:delete(fname(EB1_0, "x.beam")), + ok = file:delete(Xbeam), + ok = file:delete(Ybeam), ok. -update(suite) -> []; -update(doc) -> ["The update() function"]; +%% The update() function update(Conf) when is_list(Conf) -> CopyDir = ?copydir, Dir = fname(CopyDir,"update"), Source = fname(Dir, "x.erl"), Beam = fname(Dir, "x.beam"), - ?line copy_file(fname(Dir, "x.erl.1"), Source), - ?line {ok, x} = compile:file(Source, [debug_info, {outdir,Dir}]), - - ?line {ok, _} = start(s), - ?line ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), - ?line {ok, [x]} = xref:add_directory(s, Dir, [{builtins,true}]), - ?line {error, _, {invalid_options,[not_an_option]}} = - xref:update(s, [not_an_option]), - ?line {ok, []} = xref:update(s), - ?line {ok, [{erlang,atom_to_list,1}]} = xref:q(s, "XU"), - - ?line [{x, ModInfo}] = xref:info(s, modules, x), - ?line case keysearch(directory, 1, ModInfo) of - {value, {directory, Dir}} -> ok - end, + copy_file(fname(Dir, "x.erl.1"), Source), + {ok, x} = compile:file(Source, [debug_info, {outdir,Dir}]), + + {ok, _} = start(s), + ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), + {ok, [x]} = xref:add_directory(s, Dir, [{builtins,true}]), + {error, _, {invalid_options,[not_an_option]}} = + xref:update(s, [not_an_option]), + {ok, []} = xref:update(s), + {ok, [{erlang,atom_to_list,1}]} = xref:q(s, "XU"), + + [{x, ModInfo}] = xref:info(s, modules, x), + case keysearch(directory, 1, ModInfo) of + {value, {directory, Dir}} -> ok + end, timer:sleep(2000), % make sure modification time has changed - ?line copy_file(fname(Dir, "x.erl.2"), Source), - ?line {ok, x} = compile:file(Source, [debug_info, {outdir,Dir}]), - ?line {ok, [x]} = xref:update(s, []), - ?line {ok, [{erlang,list_to_atom,1}]} = xref:q(s, "XU"), + copy_file(fname(Dir, "x.erl.2"), Source), + {ok, x} = compile:file(Source, [debug_info, {outdir,Dir}]), + {ok, [x]} = xref:update(s, []), + {ok, [{erlang,list_to_atom,1}]} = xref:q(s, "XU"), timer:sleep(2000), - ?line {ok, x} = compile:file(Source, [no_debug_info,{outdir,Dir}]), - ?line {error, _, {no_debug_info, _}} = xref:update(s), + {ok, x} = compile:file(Source, [no_debug_info,{outdir,Dir}]), + {error, _, {no_debug_info, _}} = xref:update(s), - ?line xref:stop(s), - ?line ok = file:delete(Beam), - ?line ok = file:delete(Source), + xref:stop(s), + ok = file:delete(Beam), + ok = file:delete(Source), ok. -deprecated(suite) -> []; -deprecated(doc) -> ["OTP-4695: Deprecated functions."]; +%% OTP-4695: Deprecated functions. deprecated(Conf) when is_list(Conf) -> Dir = ?copydir, File = fname(Dir, "depr.erl"), @@ -1443,79 +1397,79 @@ deprecated(Conf) when is_list(Conf) -> %% This file has been compiled to ?datadir/depr_r9c.beam %% using the R9C compiler. From R10B and onwards the linter %% checks the 'deprecated' attribute as well. -% Test = <<"-module(depr). + % Test = <<"-module(depr). -% -export([t/0,f/1,bar/2,f/2,g/3]). + % -export([t/0,f/1,bar/2,f/2,g/3]). -% -deprecated([{f,1}, % DF -% {bar,2,eventually}]). % DF_3 -% -deprecated([{f,1,next_major_release}]). % DF_2 (again) -% -deprecated([{frutt,0,next_version}]). % message... -% -deprecated([{f,2,next_major_release}, % DF_2 -% {g,3,next_version}, % DF_1 -% {ignored,10,100}]). % message... -% -deprecated([{does_not_exist,1}]). % message... + % -deprecated([{f,1}, % DF + % {bar,2,eventually}]). % DF_3 + % -deprecated([{f,1,next_major_release}]). % DF_2 (again) + % -deprecated([{frutt,0,next_version}]). % message... + % -deprecated([{f,2,next_major_release}, % DF_2 + % {g,3,next_version}, % DF_1 + % {ignored,10,100}]). % message... + % -deprecated([{does_not_exist,1}]). % message... -% -deprecated(foo). % message... + % -deprecated(foo). % message... -% t() -> -% frutt(1), -% g(1,2, 3), -% ?MODULE:f(10). + % t() -> + % frutt(1), + % g(1,2, 3), + % ?MODULE:f(10). -% f(A) -> -% ?MODULE:f(A,A). + % f(A) -> + % ?MODULE:f(A,A). -% f(X, Y) -> -% ?MODULE:g(X, Y, X). + % f(X, Y) -> + % ?MODULE:g(X, Y, X). -% g(F, G, H) -> -% ?MODULE:bar(F, {G,H}). + % g(F, G, H) -> + % ?MODULE:bar(F, {G,H}). -% bar(_, _) -> -% true. + % bar(_, _) -> + % true. -% frutt(_) -> -% frutt(). + % frutt(_) -> + % frutt(). -% frutt() -> -% true. -% ">>, + % frutt() -> + % true. + % ">>, -% ?line ok = file:write_file(File, Test), -% ?line {ok, depr_r9c} = compile:file(File, [debug_info,{outdir,Dir}]), + % ok = file:write_file(File, Test), + % {ok, depr_r9c} = compile:file(File, [debug_info,{outdir,Dir}]), - ?line {ok, _} = xref:start(s), - ?line {ok, depr_r9c} = xref:add_module(s, MFile_r9c), + {ok, _} = xref:start(s), + {ok, depr_r9c} = xref:add_module(s, MFile_r9c), M9 = depr_r9c, DF_1 = usort([{{M9,f,2},{M9,g,3}}]), DF_2 = usort(DF_1++[{{M9,f,1},{M9,f,2}},{{M9,t,0},{M9,f,1}}]), DF_3 = usort(DF_2++[{{M9,g,3},{M9,bar,2}}]), DF = usort(DF_3++[{{M9,t,0},{M9,f,1}}]), - ?line {ok,DF} = xref:analyze(s, deprecated_function_calls), - ?line {ok,DF_1} = - xref:analyze(s, {deprecated_function_calls,next_version}), - ?line {ok,DF_2} = - xref:analyze(s, {deprecated_function_calls,next_major_release}), - ?line {ok,DF_3} = - xref:analyze(s, {deprecated_function_calls,eventually}), + {ok,DF} = xref:analyze(s, deprecated_function_calls), + {ok,DF_1} = + xref:analyze(s, {deprecated_function_calls,next_version}), + {ok,DF_2} = + xref:analyze(s, {deprecated_function_calls,next_major_release}), + {ok,DF_3} = + xref:analyze(s, {deprecated_function_calls,eventually}), D = to_external(range(from_term(DF))), D_1 = to_external(range(from_term(DF_1))), D_2 = to_external(range(from_term(DF_2))), D_3 = to_external(range(from_term(DF_3))), - ?line {ok,D} = xref:analyze(s, deprecated_functions), - ?line {ok,D_1} = - xref:analyze(s, {deprecated_functions,next_version}), - ?line {ok,D_2} = - xref:analyze(s, {deprecated_functions,next_major_release}), - ?line {ok,D_3} = - xref:analyze(s, {deprecated_functions,eventually}), + {ok,D} = xref:analyze(s, deprecated_functions), + {ok,D_1} = + xref:analyze(s, {deprecated_functions,next_version}), + {ok,D_2} = + xref:analyze(s, {deprecated_functions,next_major_release}), + {ok,D_3} = + xref:analyze(s, {deprecated_functions,eventually}), - ?line ok = check_state(s), - ?line xref:stop(s), + ok = check_state(s), + xref:stop(s), Test2= <<"-module(depr). @@ -1543,11 +1497,11 @@ deprecated(Conf) when is_list(Conf) -> ?MODULE:t(). ">>, - ?line ok = file:write_file(File, Test2), - ?line {ok, depr} = compile:file(File, [debug_info,{outdir,Dir}]), + ok = file:write_file(File, Test2), + {ok, depr} = compile:file(File, [debug_info,{outdir,Dir}]), - ?line {ok, _} = xref:start(s), - ?line {ok, depr} = xref:add_module(s, MFile), + {ok, _} = xref:start(s), + {ok, depr} = xref:add_module(s, MFile), M = depr, DFa_1 = usort([{{M,f,2},{M,g,3}}]), @@ -1555,16 +1509,16 @@ deprecated(Conf) when is_list(Conf) -> DFa_3 = usort(DFa_2++[{{M,bar,2},{M,t,0}},{{M,g,3},{M,bar,2}}]), DFa = DFa_3, - ?line {ok,DFa} = xref:analyze(s, deprecated_function_calls), - ?line {ok,DFa_1} = - xref:analyze(s, {deprecated_function_calls,next_version}), - ?line {ok,DFa_2} = - xref:analyze(s, {deprecated_function_calls,next_major_release}), - ?line {ok,DFa_3} = - xref:analyze(s, {deprecated_function_calls,eventually}), + {ok,DFa} = xref:analyze(s, deprecated_function_calls), + {ok,DFa_1} = + xref:analyze(s, {deprecated_function_calls,next_version}), + {ok,DFa_2} = + xref:analyze(s, {deprecated_function_calls,next_major_release}), + {ok,DFa_3} = + xref:analyze(s, {deprecated_function_calls,eventually}), - ?line ok = check_state(s), - ?line xref:stop(s), + ok = check_state(s), + xref:stop(s), %% All of the module is deprecated. Test3= <<"-module(depr). @@ -1592,35 +1546,34 @@ deprecated(Conf) when is_list(Conf) -> ?MODULE:t(). ">>, - ?line ok = file:write_file(File, Test3), - ?line {ok, depr} = compile:file(File, [debug_info,{outdir,Dir}]), + ok = file:write_file(File, Test3), + {ok, depr} = compile:file(File, [debug_info,{outdir,Dir}]), - ?line {ok, _} = xref:start(s), - ?line {ok, depr} = xref:add_module(s, MFile), + {ok, _} = xref:start(s), + {ok, depr} = xref:add_module(s, MFile), DFb_1 = usort([{{M,f,2},{M,g,3}}]), DFb_2 = usort(DFb_1++[{{M,f,1},{M,f,2}},{{M,t,0},{M,f,1}}]), DFb_3 = DFb_2, DFb = usort(DFb_2++[{{M,bar,2},{M,t,0}},{{M,g,3},{M,bar,2}}]), - ?line {ok,DFb} = xref:analyze(s, deprecated_function_calls), - ?line {ok,DFb_1} = - xref:analyze(s, {deprecated_function_calls,next_version}), - ?line {ok,DFb_2} = - xref:analyze(s, {deprecated_function_calls,next_major_release}), - ?line {ok,DFb_3} = - xref:analyze(s, {deprecated_function_calls,eventually}), + {ok,DFb} = xref:analyze(s, deprecated_function_calls), + {ok,DFb_1} = + xref:analyze(s, {deprecated_function_calls,next_version}), + {ok,DFb_2} = + xref:analyze(s, {deprecated_function_calls,next_major_release}), + {ok,DFb_3} = + xref:analyze(s, {deprecated_function_calls,eventually}), - ?line ok = check_state(s), - ?line xref:stop(s), + ok = check_state(s), + xref:stop(s), - ?line ok = file:delete(File), - ?line ok = file:delete(Beam), + ok = file:delete(File), + ok = file:delete(Beam), ok. -trycatch(suite) -> []; -trycatch(doc) -> ["OTP-5152: try/catch, final (?) version."]; +%% OTP-5152: try/catch, final (?) version. trycatch(Conf) when is_list(Conf) -> Dir = ?copydir, File = fname(Dir, "trycatch.erl"), @@ -1644,11 +1597,11 @@ trycatch(Conf) when is_list(Conf) -> end. ">>, - ?line ok = file:write_file(File, Test), - ?line {ok, trycatch} = compile:file(File, [debug_info,{outdir,Dir}]), + ok = file:write_file(File, Test), + {ok, trycatch} = compile:file(File, [debug_info,{outdir,Dir}]), - ?line {ok, _} = xref:start(s), - ?line {ok, trycatch} = xref:add_module(s, MFile), + {ok, _} = xref:start(s), + {ok, trycatch} = xref:add_module(s, MFile), A = trycatch, {ok,[{{{A,A,0},{bar,bar,0}},[10]}, {{{A,A,0},{bar,foo,0}},[8]}, @@ -1657,18 +1610,17 @@ trycatch(Conf) when is_list(Conf) -> {{{A,A,0},{fini,shed,0}},[15]}, {{{A,A,0},{foo,bar,0}},[7]}, {{{A,A,0},{foo,foo,0}},[9]}]} = - xref:q(s, "(Lin) (E | trycatch:trycatch/0)"), + xref:q(s, "(Lin) (E | trycatch:trycatch/0)"), - ?line ok = check_state(s), - ?line xref:stop(s), + ok = check_state(s), + xref:stop(s), - ?line ok = file:delete(File), - ?line ok = file:delete(Beam), + ok = file:delete(File), + ok = file:delete(Beam), ok. -fun_mfa(suite) -> []; -fun_mfa(doc) -> ["OTP-5653: fun M:F/A."]; +%% OTP-5653: fun M:F/A. fun_mfa(Conf) when is_list(Conf) -> Dir = ?copydir, File = fname(Dir, "fun_mfa.erl"), @@ -1693,42 +1645,42 @@ fun_mfa(Conf) when is_list(Conf) -> fun t3/0(). ">>, - ?line ok = file:write_file(File, Test), + ok = file:write_file(File, Test), A = fun_mfa, - ?line {ok, A} = compile:file(File, [debug_info,{outdir,Dir}]), - ?line {ok, _} = xref:start(s), - ?line {ok, A} = xref:add_module(s, MFile, {warnings,false}), - ?line {ok, [{{{A,t,0},{'$M_EXPR','$F_EXPR',0}},[7]}, - {{{A,t,0},{A,t,0}},[6]}, - {{{A,t1,0},{'$M_EXPR','$F_EXPR',0}},[11]}, - {{{A,t1,0},{A,t,0}},[10]}, - {{{A,t2,0},{A,t,0}},[14]}, - {{{A,t3,0},{fun_mfa,t3,0}},[17]}]} = - xref:q(s, "(Lin) E"), - - ?line ok = check_state(s), - ?line xref:stop(s), - - ?line ok = file:delete(File), - ?line ok = file:delete(Beam), + {ok, A} = compile:file(File, [debug_info,{outdir,Dir}]), + {ok, _} = xref:start(s), + {ok, A} = xref:add_module(s, MFile, {warnings,false}), + {ok, [{{{A,t,0},{'$M_EXPR','$F_EXPR',0}},[7]}, + {{{A,t,0},{A,t,0}},[6]}, + {{{A,t1,0},{'$M_EXPR','$F_EXPR',0}},[11]}, + {{{A,t1,0},{A,t,0}},[10]}, + {{{A,t2,0},{A,t,0}},[14]}, + {{{A,t3,0},{fun_mfa,t3,0}},[17]}]} = + xref:q(s, "(Lin) E"), + + ok = check_state(s), + xref:stop(s), + + ok = file:delete(File), + ok = file:delete(Beam), ok. %% Same as the previous test case, except that we use a BEAM file %% that was compiled by an R14 compiler to test backward compatibility. fun_mfa_r14(Conf) when is_list(Conf) -> - Dir = ?config(data_dir, Conf), + Dir = proplists:get_value(data_dir, Conf), MFile = fname(Dir, "fun_mfa_r14"), A = fun_mfa_r14, {ok, _} = xref:start(s), {ok, A} = xref:add_module(s, MFile, {warnings,false}), {ok, [{{{A,t,0},{'$M_EXPR','$F_EXPR',0}},[7]}, - {{{A,t,0},{A,t,0}},[6]}, - {{{A,t1,0},{'$M_EXPR','$F_EXPR',0}},[11]}, - {{{A,t1,0},{A,t,0}},[10]}, - {{{A,t2,0},{A,t,0}},[14]}, - {{{A,t3,0},{A,t3,0}},[17]}]} = - xref:q(s, "(Lin) E"), + {{{A,t,0},{A,t,0}},[6]}, + {{{A,t1,0},{'$M_EXPR','$F_EXPR',0}},[11]}, + {{{A,t1,0},{A,t,0}},[10]}, + {{{A,t2,0},{A,t,0}},[14]}, + {{{A,t3,0},{A,t3,0}},[17]}]} = + xref:q(s, "(Lin) E"), ok = check_state(s), xref:stop(s), @@ -1776,17 +1728,17 @@ fun_mfa_vars(Conf) when is_list(Conf) -> {ok, _} = xref:start(s), {ok, A} = xref:add_module(s, MFile, {warnings,false}), {ok, [{{{A,t,1},{'$M_EXPR','$F_EXPR',2}},[7]}, - {{{A,t,1},{'$M_EXPR',bar,2}},[6]}, - {{{A,t1,1},{'$M_EXPR','$F_EXPR',1}},[11]}, - {{{A,t1,1},{A,'$F_EXPR',1}},[10]}, - {{{A,t2,3},{'$M_EXPR','$F_EXPR',-1}},[14]}, - {{{A,t2,3},{'$M_EXPR','$F_EXPR',1}},[15]}, - {{{A,t3,1},{'$M_EXPR','$F_EXPR',3}},[19]}, - {{{A,t3,1},{fun_mfa_vars,t,-1}},[18]}, - {{{A,t4,2},{'$M_EXPR','$F_EXPR',3}},[22,23]}, - {{{A,t5,2},{'$M_EXPR','$F_EXPR',0}},[27]}, - {{{A,t5,2},{'$M_EXPR',t,-1}},[26]}]} = - xref:q(s, "(Lin) E"), + {{{A,t,1},{'$M_EXPR',bar,2}},[6]}, + {{{A,t1,1},{'$M_EXPR','$F_EXPR',1}},[11]}, + {{{A,t1,1},{A,'$F_EXPR',1}},[10]}, + {{{A,t2,3},{'$M_EXPR','$F_EXPR',-1}},[14]}, + {{{A,t2,3},{'$M_EXPR','$F_EXPR',1}},[15]}, + {{{A,t3,1},{'$M_EXPR','$F_EXPR',3}},[19]}, + {{{A,t3,1},{fun_mfa_vars,t,-1}},[18]}, + {{{A,t4,2},{'$M_EXPR','$F_EXPR',3}},[22,23]}, + {{{A,t5,2},{'$M_EXPR','$F_EXPR',0}},[27]}, + {{{A,t5,2},{'$M_EXPR',t,-1}},[26]}]} = + xref:q(s, "(Lin) E"), ok = check_state(s), xref:stop(s), @@ -1795,8 +1747,7 @@ fun_mfa_vars(Conf) when is_list(Conf) -> ok = file:delete(Beam), ok. -qlc(suite) -> []; -qlc(doc) -> ["OTP-5195: A bug fix when using qlc:q/1,2."]; +%% OTP-5195: A bug fix when using qlc:q/1,2. qlc(Conf) when is_list(Conf) -> Dir = ?copydir, File = fname(Dir, "qlc.erl"), @@ -1821,32 +1772,31 @@ qlc(Conf) when is_list(Conf) -> ok. ">>, - ?line ok = file:write_file(File, Test), + ok = file:write_file(File, Test), A = qlc, - ?line {ok, A} = compile:file(File, [debug_info,{outdir,Dir}]), - ?line {ok, _} = xref:start(s), - ?line {ok, A} = xref:add_module(s, MFile, {warnings,false}), - ?line {ok, _} = xref:q(s, "(Lin) E"), % is can be loaded + {ok, A} = compile:file(File, [debug_info,{outdir,Dir}]), + {ok, _} = xref:start(s), + {ok, A} = xref:add_module(s, MFile, {warnings,false}), + {ok, _} = xref:q(s, "(Lin) E"), % is can be loaded - ?line ok = check_state(s), - ?line xref:stop(s), + ok = check_state(s), + xref:stop(s), - ?line ok = file:delete(File), - ?line ok = file:delete(Beam), + ok = file:delete(File), + ok = file:delete(Beam), ok. -analyze(suite) -> []; -analyze(doc) -> ["Simple analyses"]; +%% Simple analyses analyze(Conf) when is_list(Conf) -> S0 = new(), - ?line {{error, _, {invalid_options,[not_an_option]}}, _} = - xref_base:analyze(S0, undefined_function_calls, [not_an_option]), - ?line {{error, _, {invalid_query,{q}}}, _} = xref_base:q(S0,{q}), - ?line {{error, _, {unknown_analysis,foo}}, _} = xref_base:analyze(S0, foo), - ?line {{error, _, {unknown_constant,"foo:bar/-1"}}, _} = - xref_base:analyze(S0, {use,{foo,bar,-1}}), + {{error, _, {invalid_options,[not_an_option]}}, _} = + xref_base:analyze(S0, undefined_function_calls, [not_an_option]), + {{error, _, {invalid_query,{q}}}, _} = xref_base:q(S0,{q}), + {{error, _, {unknown_analysis,foo}}, _} = xref_base:analyze(S0, foo), + {{error, _, {unknown_constant,"foo:bar/-1"}}, _} = + xref_base:analyze(S0, {use,{foo,bar,-1}}), CopyDir = ?copydir, Dir = fname(CopyDir,"rel2"), @@ -1859,57 +1809,50 @@ analyze(Conf) when is_list(Conf) -> Xbeam = fname(EB2, "x.beam"), Ybeam = fname(EB1_1, "y.beam"), - ?line {ok, x} = compile:file(X, [debug_info, {outdir,EB2}]), - ?line {ok, y} = compile:file(Y, [debug_info, {outdir,EB1_1}]), - - ?line {ok, rel2, S1} = xref_base:add_release(S0, Dir, [{verbose,false}]), - ?line S = set_up(S1), - - ?line {ok, _} = - analyze(undefined_function_calls, [{{x,xx,0},{x,undef,0}}], S), - ?line {ok, _} = analyze(undefined_functions, [{x,undef,0}], S), - ?line {ok, _} = analyze(locals_not_used, [{x,l,0},{x,l1,0}], S), - ?line {ok, _} = analyze(exports_not_used, [{x,xx,0},{y,t,0}], S), - - ?line {ok, _} = - analyze(deprecated_function_calls, [{{y,t,0},{x,t,0}}], S), - ?line {ok, _} = analyze({deprecated_function_calls,next_version}, [], S), - ?line {ok, _} = - analyze({deprecated_function_calls,next_major_release}, [], S), - ?line {ok, _} = analyze({deprecated_function_calls,eventually}, - [{{y,t,0},{x,t,0}}], S), - ?line {ok, _} = analyze(deprecated_functions, [{x,t,0}], S), - ?line {ok, _} = analyze({deprecated_functions,next_version}, [], S), - ?line {ok, _} = - analyze({deprecated_functions,next_major_release}, [], S), - ?line {ok, _} = analyze({deprecated_functions,eventually}, [{x,t,0}], S), - - ?line {ok, _} = analyze({call, {x,xx,0}}, [{x,undef,0}], S), - ?line {ok, _} = - analyze({call, [{x,xx,0},{x,l,0}]}, [{x,l1,0},{x,undef,0}], S), - ?line {ok, _} = analyze({use, {x,l,0}}, [{x,l1,0}], S), - ?line {ok, _} = - analyze({use, [{x,l,0},{x,l1,0}]}, [{x,l,0},{x,l1,0}], S), - - ?line {ok, _} = analyze({module_call, x}, [x], S), - ?line {ok, _} = analyze({module_call, [x,y]}, [x], S), - ?line {ok, _} = analyze({module_use, x}, [x,y], S), - ?line {ok, _} = analyze({module_use, [x,y]}, [x,y], S), - - ?line {ok, _} = analyze({application_call, app1}, [app2], S), - ?line {ok, _} = analyze({application_call, [app1,app2]}, [app2], S), - ?line {ok, _} = analyze({application_use, app2}, [app1,app2], S), - ?line {ok, _} = analyze({application_use, [app1,app2]}, [app1,app2], S), - - ?line ok = xref_base:delete(S), - ?line ok = file:delete(Xbeam), - ?line ok = file:delete(Ybeam), + {ok, x} = compile:file(X, [debug_info, {outdir,EB2}]), + {ok, y} = compile:file(Y, [debug_info, {outdir,EB1_1}]), + + {ok, rel2, S1} = xref_base:add_release(S0, Dir, [{verbose,false}]), + S = set_up(S1), + + {ok, _} = analyze(undefined_function_calls, [{{x,xx,0},{x,undef,0}}], S), + {ok, _} = analyze(undefined_functions, [{x,undef,0}], S), + {ok, _} = analyze(locals_not_used, [{x,l,0},{x,l1,0}], S), + {ok, _} = analyze(exports_not_used, [{x,xx,0},{y,t,0}], S), + + {ok, _} = analyze(deprecated_function_calls, [{{y,t,0},{x,t,0}}], S), + {ok, _} = analyze({deprecated_function_calls,next_version}, [], S), + {ok, _} = analyze({deprecated_function_calls,next_major_release}, [], S), + {ok, _} = analyze({deprecated_function_calls,eventually}, + [{{y,t,0},{x,t,0}}], S), + {ok, _} = analyze(deprecated_functions, [{x,t,0}], S), + {ok, _} = analyze({deprecated_functions,next_version}, [], S), + {ok, _} = analyze({deprecated_functions,next_major_release}, [], S), + {ok, _} = analyze({deprecated_functions,eventually}, [{x,t,0}], S), + + {ok, _} = analyze({call, {x,xx,0}}, [{x,undef,0}], S), + {ok, _} = analyze({call, [{x,xx,0},{x,l,0}]}, [{x,l1,0},{x,undef,0}], S), + {ok, _} = analyze({use, {x,l,0}}, [{x,l1,0}], S), + {ok, _} = analyze({use, [{x,l,0},{x,l1,0}]}, [{x,l,0},{x,l1,0}], S), + + {ok, _} = analyze({module_call, x}, [x], S), + {ok, _} = analyze({module_call, [x,y]}, [x], S), + {ok, _} = analyze({module_use, x}, [x,y], S), + {ok, _} = analyze({module_use, [x,y]}, [x,y], S), + + {ok, _} = analyze({application_call, app1}, [app2], S), + {ok, _} = analyze({application_call, [app1,app2]}, [app2], S), + {ok, _} = analyze({application_use, app2}, [app1,app2], S), + {ok, _} = analyze({application_use, [app1,app2]}, [app1,app2], S), + + ok = xref_base:delete(S), + ok = file:delete(Xbeam), + ok = file:delete(Ybeam), ok. -basic(suite) -> []; -basic(doc) -> ["Use of operators"]; +%% Use of operators basic(Conf) when is_list(Conf) -> - ?line S0 = new(), + S0 = new(), F1 = {m1,f1,1}, F6 = {m1,f2,6}, % X @@ -1943,8 +1886,8 @@ basic(Conf) when is_list(Conf) -> LCallAt_m1 = [{E7,12}], XCallAt_m1 = [{E1,13},{E2,17},{E4,7}], Info1 = #xref_mod{name = m1, app_name = [a1]}, - ?line S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, - XC_m1, LC_m1), + S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, + XC_m1, LC_m1), D2 = {F2,7}, D3 = {F3,9}, @@ -1957,8 +1900,8 @@ basic(Conf) when is_list(Conf) -> LCallAt_m2 = [], XCallAt_m2 = [{E3,96},{E6,12},{UE1,77}], Info2 = #xref_mod{name = m2, app_name = [a2]}, - ?line S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, - XC_m2, LC_m2), + S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, + XC_m2, LC_m2), D4 = {F4,6}, D5 = {F5,97}, @@ -1970,186 +1913,185 @@ basic(Conf) when is_list(Conf) -> LCallAt_m3 = [{E5,19}], XCallAt_m3 = [{UE2,22}], Info3 = #xref_mod{name = m3, app_name = [a3]}, - ?line S3 = add_module(S2, Info3, DefAt_m3, X_m3, LCallAt_m3, XCallAt_m3, - XC_m3, LC_m3), + S3 = add_module(S2, Info3, DefAt_m3, X_m3, LCallAt_m3, XCallAt_m3, + XC_m3, LC_m3), Info4 = #xref_mod{name = m4, app_name = [a2]}, - ?line S4 = add_module(S3, Info4, [], [], [], [], [], []), + S4 = add_module(S3, Info4, [], [], [], [], [], []), AppInfo1 = #xref_app{name = a1, rel_name = [r1]}, - ?line S9 = add_application(S4, AppInfo1), + S9 = add_application(S4, AppInfo1), AppInfo2 = #xref_app{name = a2, rel_name = [r1]}, - ?line S10 = add_application(S9, AppInfo2), + S10 = add_application(S9, AppInfo2), AppInfo3 = #xref_app{name = a3, rel_name = [r2]}, - ?line S11 = add_application(S10, AppInfo3), + S11 = add_application(S10, AppInfo3), RelInfo1 = #xref_rel{name = r1}, - ?line S12 = add_release(S11, RelInfo1), + S12 = add_release(S11, RelInfo1), RelInfo2 = #xref_rel{name = r2}, - ?line S13 = add_release(S12, RelInfo2), + S13 = add_release(S12, RelInfo2), - ?line S = set_up(S13), + S = set_up(S13), - ?line {ok, _} = eval("[m1,m2] + m:f/1", unknown_constant, S), - ?line {ok, _} = eval("[m1, m2, m:f/1]", type_mismatch, S), + {ok, _} = eval("[m1,m2] + m:f/1", unknown_constant, S), + {ok, _} = eval("[m1, m2, m:f/1]", type_mismatch, S), - ?line {ok, _} = eval("[m1, m1->m2]", type_mismatch, S), - ?line {ok, _} = eval("components:f/1", unknown_constant, S), - ?line {ok, _} = eval("'of':f/1", unknown_constant, S), - ?line {ok, _} = eval("of:f/1", parse_error, S), - ?line {ok, _} = eval("components", unknown_constant, S), - ?line {ok, _} = eval("[components, of, closure]", parse_error, S), - ?line {ok, _} = eval("[components, 'of', closure]", unknown_constant, S), + {ok, _} = eval("[m1, m1->m2]", type_mismatch, S), + {ok, _} = eval("components:f/1", unknown_constant, S), + {ok, _} = eval("'of':f/1", unknown_constant, S), + {ok, _} = eval("of:f/1", parse_error, S), + {ok, _} = eval("components", unknown_constant, S), + {ok, _} = eval("[components, of, closure]", parse_error, S), + {ok, _} = eval("[components, 'of', closure]", unknown_constant, S), - ?line {ok, _} = eval("[a1->a2,m1->m2]", type_mismatch, S), - ?line {ok, _} = eval("a1->a2,m1->m2", parse_error, S), + {ok, _} = eval("[a1->a2,m1->m2]", type_mismatch, S), + {ok, _} = eval("a1->a2,m1->m2", parse_error, S), - ?line {ok, _} = eval("m1->a1", type_mismatch, S), - ?line {ok, _} = eval("[{m1,f1,1}] : App", parse_error, S), - ?line {ok, _} = eval("[{m1,f1,1}] : Fun", [F1], S), - ?line {ok, _} = eval("range X", type_error, S), - ?line {ok, _} = eval("domain X", type_error, S), - ?line {ok, _} = eval("range M", type_error, S), - ?line {ok, _} = eval("domain M", type_error, S), + {ok, _} = eval("m1->a1", type_mismatch, S), + {ok, _} = eval("[{m1,f1,1}] : App", parse_error, S), + {ok, _} = eval("[{m1,f1,1}] : Fun", [F1], S), + {ok, _} = eval("range X", type_error, S), + {ok, _} = eval("domain X", type_error, S), + {ok, _} = eval("range M", type_error, S), + {ok, _} = eval("domain M", type_error, S), % Misc. - ?line {ok, _} = eval("not_a_prefix_operator m1", parse_error, S), - ?line {ok, _} = eval(f("(Mod) ~p", [[F1,F6,F5]]), [m1,m3], S), - ?line {ok, _} = eval("(Lin) M - (Lin) m1", - [{F2,7},{F3,9},{F7,19},{F4,6},{F5,97},{UF2,0}], S), - ?line {ok, _} = eval(f("(Lin) M * (Lin) ~p", [[F1,F6]]), - [{F1,12},{F6,3}], S), - - ?line {ok, _} = eval(f("X * ~p", [[F1, F2, F3, F4, F5]]), [F3, F4], S), - ?line {ok, _} = eval("X", [F6,F3,F7,F4], S), - ?line {ok, _} = eval("X * AM", [F6,F3,F7,F4], S), - ?line {ok, _} = eval("X * a2", [F3,F7], S), - - ?line {ok, _} = eval("L * r1", [F1,F2], S), - ?line {ok, _} = eval("U", [UF1, UF2], S), - ?line {ok, _} = eval("U * AM", [UF1], S), - ?line {ok, _} = eval("U * UM", [UF2], S), - ?line {ok, _} = eval("XU * [m1, m2]", [F6,F3,F7,UF1], S), - ?line {ok, _} = eval("LU * [m3, m4]", [F5], S), - ?line {ok, _} = eval("UU", [F1,F2], S), - - ?line {ok, _} = eval("XC | m1", [E1,E2,E4], S), - ?line {ok, _} = eval(f("XC | ~p", [F1]), [E1,E4], S), - ?line {ok, _} = eval(f("(XXL) (Lin) (XC | ~p)", [F1]), - [{{D1,D3},[13]},{{D1,D4},[7]}],S), - ?line {ok, _} = eval(f("XC | (~p + ~p)", [F1, F2]), [E1,E4,E3,UE1], S), - ?line {ok, _} = eval(f("(XXL) (Lin) (XC | ~p)", [F1]), - [{{D1,D3},[13]},{{D1,D4},[7]}], S), - ?line {ok, _} = eval("LC | m3", [E5], S), - ?line {ok, _} = eval(f("LC | ~p", [F1]), [E7], S), - ?line {ok, _} = eval(f("LC | (~p + ~p)", [F1, F4]), [E7, E5], S), - ?line {ok, _} = eval("E | m1", [E1,E2,E4,E7], S), - ?line {ok, _} = eval(f("E | ~p", [F1]), [E1,E7,E4], S), - ?line {ok, _} = eval(f("E | (~p + ~p)", [F1, F2]), [E1,E7,E4,E3,UE1], S), - - ?line {ok, _} = eval("XC || m1", [E3,UE2], S), - ?line {ok, _} = eval(f("XC || ~p", [F6]), [E3], S), - ?line {ok, _} = eval(f("XC || (~p + ~p)", [F4, UF2]), [UE1,E4,E6], S), - ?line {ok, _} = eval("LC || m3", [E5], S), - ?line {ok, _} = eval(f("LC || ~p", [F1]), [], S), - ?line {ok, _} = eval(f("LC || ~p", [F6]), [E7], S), - ?line {ok, _} = eval(f("LC || (~p + ~p)", [F5, F6]), [E7,E5], S), - ?line {ok, _} = eval("E || m1", [E3,UE2,E7], S), - ?line {ok, _} = eval(f("E || ~p", [F6]), [E3,E7], S), - ?line {ok, _} = eval(f("E || (~p + ~p)", [F3,F4]), [E1,E4,E6], S), - - ?line {ok, _} = eval(f("~p + ~p", [F1,F2]), [F1,F2], S), - ?line {ok, _} = eval(f("~p * ~p", [m1,[F1,F6,F2]]), [F1,F6], S), - ?line {ok, _} = eval(f("~p * ~p", [F1,F2]), [], S), + {ok, _} = eval("not_a_prefix_operator m1", parse_error, S), + {ok, _} = eval(f("(Mod) ~p", [[F1,F6,F5]]), [m1,m3], S), + {ok, _} = eval("(Lin) M - (Lin) m1", + [{F2,7},{F3,9},{F7,19},{F4,6},{F5,97},{UF2,0}], S), + {ok, _} = eval(f("(Lin) M * (Lin) ~p", [[F1,F6]]), + [{F1,12},{F6,3}], S), + + {ok, _} = eval(f("X * ~p", [[F1, F2, F3, F4, F5]]), [F3, F4], S), + {ok, _} = eval("X", [F6,F3,F7,F4], S), + {ok, _} = eval("X * AM", [F6,F3,F7,F4], S), + {ok, _} = eval("X * a2", [F3,F7], S), + + {ok, _} = eval("L * r1", [F1,F2], S), + {ok, _} = eval("U", [UF1, UF2], S), + {ok, _} = eval("U * AM", [UF1], S), + {ok, _} = eval("U * UM", [UF2], S), + {ok, _} = eval("XU * [m1, m2]", [F6,F3,F7,UF1], S), + {ok, _} = eval("LU * [m3, m4]", [F5], S), + {ok, _} = eval("UU", [F1,F2], S), + + {ok, _} = eval("XC | m1", [E1,E2,E4], S), + {ok, _} = eval(f("XC | ~p", [F1]), [E1,E4], S), + {ok, _} = eval(f("(XXL) (Lin) (XC | ~p)", [F1]), + [{{D1,D3},[13]},{{D1,D4},[7]}],S), + {ok, _} = eval(f("XC | (~p + ~p)", [F1, F2]), [E1,E4,E3,UE1], S), + {ok, _} = eval(f("(XXL) (Lin) (XC | ~p)", [F1]), + [{{D1,D3},[13]},{{D1,D4},[7]}], S), + {ok, _} = eval("LC | m3", [E5], S), + {ok, _} = eval(f("LC | ~p", [F1]), [E7], S), + {ok, _} = eval(f("LC | (~p + ~p)", [F1, F4]), [E7, E5], S), + {ok, _} = eval("E | m1", [E1,E2,E4,E7], S), + {ok, _} = eval(f("E | ~p", [F1]), [E1,E7,E4], S), + {ok, _} = eval(f("E | (~p + ~p)", [F1, F2]), [E1,E7,E4,E3,UE1], S), + + {ok, _} = eval("XC || m1", [E3,UE2], S), + {ok, _} = eval(f("XC || ~p", [F6]), [E3], S), + {ok, _} = eval(f("XC || (~p + ~p)", [F4, UF2]), [UE1,E4,E6], S), + {ok, _} = eval("LC || m3", [E5], S), + {ok, _} = eval(f("LC || ~p", [F1]), [], S), + {ok, _} = eval(f("LC || ~p", [F6]), [E7], S), + {ok, _} = eval(f("LC || (~p + ~p)", [F5, F6]), [E7,E5], S), + {ok, _} = eval("E || m1", [E3,UE2,E7], S), + {ok, _} = eval(f("E || ~p", [F6]), [E3,E7], S), + {ok, _} = eval(f("E || (~p + ~p)", [F3,F4]), [E1,E4,E6], S), + + {ok, _} = eval(f("~p + ~p", [F1,F2]), [F1,F2], S), + {ok, _} = eval(f("~p * ~p", [m1,[F1,F6,F2]]), [F1,F6], S), + {ok, _} = eval(f("~p * ~p", [F1,F2]), [], S), %% range, domain - ?line {ok, _} = eval("range (E || m1)", [F6,UF1], S), - ?line {ok, _} = eval("domain (E || m1)", [F1,F2,F5], S), - ?line {ok, _} = eval(f("E | domain ~p", [[E1, {F2,F4}]]), - [E1,E7,E4,E3,UE1], S), + {ok, _} = eval("range (E || m1)", [F6,UF1], S), + {ok, _} = eval("domain (E || m1)", [F1,F2,F5], S), + {ok, _} = eval(f("E | domain ~p", [[E1, {F2,F4}]]), + [E1,E7,E4,E3,UE1], S), %% components, condensation, use, call - ?line {ok, _} = eval("(Lin) components E", type_error, S), - ?line {ok, _} = eval("components (Lin) E", type_error, S), - ?line {ok, _} = eval("components V", type_error, S), - ?line {ok, _} = eval("components E + components E", type_error, S), - - ?line {ok, _} = eval(f("range (closure E | ~p)", [[F1,F2]]), - [F6,F3,F7,F4,F5,UF1,UF2], S), - ?line {ok, _} = - eval(f("domain (closure E || ~p)", [[UF2,F7]]), [F1,F2,F6], S), - ?line {ok, _} = eval("components E", [], S), - ?line {ok, _} = eval("components (Mod) E", [[m1,m2,m3]], S), - ?line {ok, _} = eval("components closure (Mod) E", [[m1,m2,m3]], S), - ?line {ok, _} = eval("condensation (Mod) E", - [{[m1,m2,m3],[m17]}], S), - ?line {ok, _} = eval("condensation closure (Mod) E", - [{[m1,m2,m3],[m17]}], S), - ?line {ok, _} = eval("condensation closure closure closure (Mod) E", - [{[m1,m2,m3],[m17]}], S), - ?line {ok, _} = eval("weak condensation (Mod) E", - [{[m1,m2,m3],[m1,m2,m3]},{[m1,m2,m3],[m17]},{[m17],[m17]}], S), - ?line {ok, _} = eval("strict condensation (Mod) E", - [{[m1,m2,m3],[m17]}], S), - ?line {ok, _} = eval("range condensation (Mod) E", - [[m17]], S), - ?line {ok, _} = eval("domain condensation (Mod) E", - [[m1,m2,m3]], S), + {ok, _} = eval("(Lin) components E", type_error, S), + {ok, _} = eval("components (Lin) E", type_error, S), + {ok, _} = eval("components V", type_error, S), + {ok, _} = eval("components E + components E", type_error, S), + + {ok, _} = eval(f("range (closure E | ~p)", [[F1,F2]]), + [F6,F3,F7,F4,F5,UF1,UF2], S), + {ok, _} = + eval(f("domain (closure E || ~p)", [[UF2,F7]]), [F1,F2,F6], S), + {ok, _} = eval("components E", [], S), + {ok, _} = eval("components (Mod) E", [[m1,m2,m3]], S), + {ok, _} = eval("components closure (Mod) E", [[m1,m2,m3]], S), + {ok, _} = eval("condensation (Mod) E", + [{[m1,m2,m3],[m17]}], S), + {ok, _} = eval("condensation closure (Mod) E", + [{[m1,m2,m3],[m17]}], S), + {ok, _} = eval("condensation closure closure closure (Mod) E", + [{[m1,m2,m3],[m17]}], S), + {ok, _} = eval("weak condensation (Mod) E", + [{[m1,m2,m3],[m1,m2,m3]},{[m1,m2,m3],[m17]},{[m17],[m17]}], S), + {ok, _} = eval("strict condensation (Mod) E", + [{[m1,m2,m3],[m17]}], S), + {ok, _} = eval("range condensation (Mod) E", + [[m17]], S), + {ok, _} = eval("domain condensation (Mod) E", + [[m1,m2,m3]], S), %% |, ||, ||| - ?line {ok, _} = eval("(Lin) E || V", type_error, S), - ?line {ok, _} = eval("E ||| (Lin) V", type_error, S), - ?line {ok, _} = eval("E ||| m1", [E7], S), - ?line {ok, _} = eval("closure E ||| m1", [E7,{F1,UF1},{F6,UF1}], S), - ?line {ok, _} = eval("closure E ||| [m1,m2]", - [{F1,UF1},{F2,F7},{F1,F7},{F6,UF1},{F2,UF1},{F7,UF1},E7,E1,E2,E3], S), - ?line {ok, _} = eval("AE | a1", [{a1,a1},{a1,a2},{a1,a3}], S), + {ok, _} = eval("(Lin) E || V", type_error, S), + {ok, _} = eval("E ||| (Lin) V", type_error, S), + {ok, _} = eval("E ||| m1", [E7], S), + {ok, _} = eval("closure E ||| m1", [E7,{F1,UF1},{F6,UF1}], S), + {ok, _} = eval("closure E ||| [m1,m2]", + [{F1,UF1},{F2,F7},{F1,F7},{F6,UF1},{F2,UF1},{F7,UF1},E7,E1,E2,E3], S), + {ok, _} = eval("AE | a1", [{a1,a1},{a1,a2},{a1,a3}], S), %% path ('of') - ?line {ok, _} = eval("(Lin) {m1,m2} of E", type_error, S), - ?line {ok, _} = eval("{m1,m2} of (Lin) E", type_error, S), - ?line [m1,m2] = eval("{m1,m2} of {m1,m2}", S), - ?line {ok, _} = eval("{m1,m2} of m1", type_error, S), - ?line {ok, _} = eval("{a3,m1} of ME", type_mismatch, S), - ?line [m1,m1] = eval("{m1} of ME", S), - ?line [m1,m1] = eval("{m1} of closure closure ME", S), - ?line false = eval("{m17} of ME", S), - ?line [m2,m1,m2] = eval("{m2} : Mod of ME", S), - ?line [m1,m2,m17] = eval("{m1, m17} of ME", S), - ?line [m1,m2,m17] = eval("m1 -> m17 of ME", S), - ?line {ok, _} = eval("[m1->m17,m17->m1] of ME", type_error, S), - ?line case eval(f("~p of E", [{F1,F7,UF1}]), S) of - [F1,F6,F7,F4,F5,UF1] -> ok - end, - ?line [a2,a1,a2] = eval("{a2} of AE", S), + {ok, _} = eval("(Lin) {m1,m2} of E", type_error, S), + {ok, _} = eval("{m1,m2} of (Lin) E", type_error, S), + [m1,m2] = eval("{m1,m2} of {m1,m2}", S), + {ok, _} = eval("{m1,m2} of m1", type_error, S), + {ok, _} = eval("{a3,m1} of ME", type_mismatch, S), + [m1,m1] = eval("{m1} of ME", S), + [m1,m1] = eval("{m1} of closure closure ME", S), + false = eval("{m17} of ME", S), + [m2,m1,m2] = eval("{m2} : Mod of ME", S), + [m1,m2,m17] = eval("{m1, m17} of ME", S), + [m1,m2,m17] = eval("m1 -> m17 of ME", S), + {ok, _} = eval("[m1->m17,m17->m1] of ME", type_error, S), + case eval(f("~p of E", [{F1,F7,UF1}]), S) of + [F1,F6,F7,F4,F5,UF1] -> ok + end, + [a2,a1,a2] = eval("{a2} of AE", S), %% weak/strict - ?line {ok, _} = eval("weak {m1,m2}", [{m1,m1},{m1,m2},{m2,m2}], S), - ?line {ok, _} = eval("strict [{m1,m1},{m1,m2},{m2,m2}]", [{m1,m2}], S), - ?line {ok, _} = eval("range weak [{m1,m2}] : Mod", [m1,m2], S), - ?line {ok, _} = eval("domain strict [{m1,m1},{m1,m2},{m2,m2}]", [m1], S), + {ok, _} = eval("weak {m1,m2}", [{m1,m1},{m1,m2},{m2,m2}], S), + {ok, _} = eval("strict [{m1,m1},{m1,m2},{m2,m2}]", [{m1,m2}], S), + {ok, _} = eval("range weak [{m1,m2}] : Mod", [m1,m2], S), + {ok, _} = eval("domain strict [{m1,m1},{m1,m2},{m2,m2}]", [m1], S), %% #, number of - ?line {ok, _} = eval("# [{r1,r2}] : Rel", 1, S), - ?line {ok, _} = eval("# [{a3,a1}] : App", 1, S), - ?line {ok, _} = eval("# AE", 7, S), - ?line {ok, _} = eval("# ME", 8, S), - ?line {ok, _} = eval("# AE + # ME", 15, S), - ?line {ok, _} = eval("# AE * # ME", 56, S), - ?line {ok, _} = eval("# AE - # ME", -1, S), - ?line {ok, _} = eval("# E", 9, S), - ?line {ok, _} = eval("# V", 9, S), - ?line {ok, _} = eval("# (Lin) E", 9, S), - ?line {ok, _} = eval("# (ELin) E", 7, S), - ?line {ok, _} = eval("# closure E", type_error, S), - ?line {ok, _} = eval("# weak {m1,m2}", 3, S), - ?line {ok, _} = eval("#strict condensation (Mod) E", 1, S), - ?line {ok, _} = eval("#components closure (Mod) E", 1, S), - ?line {ok, _} = eval("# range strict condensation (Mod) E", 1, S), + {ok, _} = eval("# [{r1,r2}] : Rel", 1, S), + {ok, _} = eval("# [{a3,a1}] : App", 1, S), + {ok, _} = eval("# AE", 7, S), + {ok, _} = eval("# ME", 8, S), + {ok, _} = eval("# AE + # ME", 15, S), + {ok, _} = eval("# AE * # ME", 56, S), + {ok, _} = eval("# AE - # ME", -1, S), + {ok, _} = eval("# E", 9, S), + {ok, _} = eval("# V", 9, S), + {ok, _} = eval("# (Lin) E", 9, S), + {ok, _} = eval("# (ELin) E", 7, S), + {ok, _} = eval("# closure E", type_error, S), + {ok, _} = eval("# weak {m1,m2}", 3, S), + {ok, _} = eval("#strict condensation (Mod) E", 1, S), + {ok, _} = eval("#components closure (Mod) E", 1, S), + {ok, _} = eval("# range strict condensation (Mod) E", 1, S), ok. -md(suite) -> []; -md(doc) -> ["The xref:m() and xref:d() functions"]; +%% The xref:m() and xref:d() functions md(Conf) when is_list(Conf) -> CopyDir = ?copydir, Dir = fname(CopyDir,"md"), @@ -2158,63 +2100,61 @@ md(Conf) when is_list(Conf) -> Xbeam = fname(Dir, "x__x.beam"), Ybeam = fname(Dir, "y__y.beam"), - ?line {error, _, {invalid_filename,{foo,bar}}} = xref:m({foo,bar}), - ?line {error, _, {invalid_filename,{foo,bar}}} = xref:d({foo,bar}), + {error, _, {invalid_filename,{foo,bar}}} = xref:m({foo,bar}), + {error, _, {invalid_filename,{foo,bar}}} = xref:d({foo,bar}), - ?line {ok, x__x} = compile:file(X, [debug_info, {outdir,Dir}]), - ?line {ok, y__y} = compile:file(Y, [debug_info, {outdir,Dir}]), + {ok, x__x} = compile:file(X, [debug_info, {outdir,Dir}]), + {ok, y__y} = compile:file(Y, [debug_info, {outdir,Dir}]), - ?line {error, _, {no_such_module, foo_bar}} = xref:m(foo_bar), - ?line OldPath = code:get_path(), - ?line true = code:set_path([Dir | OldPath]), - ?line MInfo = xref:m(x__x), - ?line [{{x__x,t,1},{y__y,t,2}}] = info_tag(MInfo, undefined), - ?line [] = info_tag(MInfo, unused), - ?line [] = info_tag(MInfo, deprecated), - ?line DInfo = xref:d(Dir), - ?line [{{x__x,t,1},{y__y,t,2}}] = info_tag(DInfo, undefined), - ?line [{y__y,l,0},{y__y,l1,0}] = info_tag(DInfo, unused), - ?line [] = info_tag(MInfo, deprecated), + {error, _, {no_such_module, foo_bar}} = xref:m(foo_bar), + OldPath = code:get_path(), + true = code:set_path([Dir | OldPath]), + MInfo = xref:m(x__x), + [{{x__x,t,1},{y__y,t,2}}] = info_tag(MInfo, undefined), + [] = info_tag(MInfo, unused), + [] = info_tag(MInfo, deprecated), + DInfo = xref:d(Dir), + [{{x__x,t,1},{y__y,t,2}}] = info_tag(DInfo, undefined), + [{y__y,l,0},{y__y,l1,0}] = info_tag(DInfo, unused), + [] = info_tag(MInfo, deprecated), %% Switch from 'functions' mode to 'modules' mode. - ?line {ok, x__x} = compile:file(X, [no_debug_info, {outdir,Dir}]), - ?line {ok, y__y} = compile:file(Y, [no_debug_info, {outdir,Dir}]), - ?line MInfoMod = xref:m(x__x), - ?line [{y__y,t,2}] = info_tag(MInfoMod, undefined), - ?line [] = info_tag(MInfo, deprecated), - ?line DInfoMod = xref:d(Dir), - ?line [{y__y,t,2}] = info_tag(DInfoMod, undefined), - ?line [] = info_tag(MInfo, deprecated), - - ?line true = code:set_path(OldPath), - ?line ok = file:delete(Xbeam), - ?line ok = file:delete(Ybeam), + {ok, x__x} = compile:file(X, [no_debug_info, {outdir,Dir}]), + {ok, y__y} = compile:file(Y, [no_debug_info, {outdir,Dir}]), + MInfoMod = xref:m(x__x), + [{y__y,t,2}] = info_tag(MInfoMod, undefined), + [] = info_tag(MInfo, deprecated), + DInfoMod = xref:d(Dir), + [{y__y,t,2}] = info_tag(DInfoMod, undefined), + [] = info_tag(MInfo, deprecated), + + true = code:set_path(OldPath), + ok = file:delete(Xbeam), + ok = file:delete(Ybeam), ok. -q(suite) -> []; -q(doc) -> ["User queries"]; +%% User queries q(Conf) when is_list(Conf) -> - ?line S0 = new(), - ?line {ok, _} = eval("'foo", parse_error, S0), - ?line {ok, _} = eval("TT = E, TT = V", variable_reassigned, S0), - ?line {ok, _} = eval("TT = E, TTT", unknown_variable, S0), - ?line {ok, S} = eval("TT := E", [], S0), - ?line {ok, S1} = eval("TT * TT * TT", [], S), - ?line {ok, _S2} = xref_base:forget(S1, 'TT'), + S0 = new(), + {ok, _} = eval("'foo", parse_error, S0), + {ok, _} = eval("TT = E, TT = V", variable_reassigned, S0), + {ok, _} = eval("TT = E, TTT", unknown_variable, S0), + {ok, S} = eval("TT := E", [], S0), + {ok, S1} = eval("TT * TT * TT", [], S), + {ok, _S2} = xref_base:forget(S1, 'TT'), ok. -variables(suite) -> []; -variables(doc) -> ["Setting and getting values of query variables"]; +%% Setting and getting values of query variables variables(Conf) when is_list(Conf) -> - ?line Sa = new(), - ?line {{error, _, {invalid_options,[not_an_option]}}, _} = - xref_base:variables(Sa, [not_an_option]), - ?line {error, _, {not_user_variable,foo}} = xref_base:forget(Sa, foo), - ?line Sa1 = set_up(Sa), - ?line {error, _, {not_user_variable,foo}} = xref_base:forget(Sa1, foo), - ?line ok = xref_base:delete(Sa1), + Sa = new(), + {{error, _, {invalid_options,[not_an_option]}}, _} = + xref_base:variables(Sa, [not_an_option]), + {error, _, {not_user_variable,foo}} = xref_base:forget(Sa, foo), + Sa1 = set_up(Sa), + {error, _, {not_user_variable,foo}} = xref_base:forget(Sa1, foo), + ok = xref_base:delete(Sa1), - ?line S0 = new(), + S0 = new(), F1 = {m1,f1,1}, F2 = {m2,f1,2}, @@ -2233,8 +2173,8 @@ variables(Conf) when is_list(Conf) -> LCallAt_m1 = [], XCallAt_m1 = [{E1,13},{E3,17}], Info1 = #xref_mod{name = m1, app_name = [a1]}, - ?line S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, - XC_m1, LC_m1), + S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, + XC_m1, LC_m1), D2 = {F2,7}, DefAt_m2 = [D2], @@ -2245,66 +2185,65 @@ variables(Conf) when is_list(Conf) -> LCallAt_m2 = [], XCallAt_m2 = [{E2,96}], Info2 = #xref_mod{name = m2, app_name = [a2]}, - ?line S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, - XC_m2, LC_m2), - - ?line S = set_up(S2), - - ?line eval("T1=E, T2=E*T1, T3 = T2*T2, T4=range T3, T5=T3|T4, T5", - [E1,E2,E3], S), - ?line eval("((E*E)*(E*E)) | (range ((E*E)*(E*E)))", - [E1,E2,E3], S), - ?line eval("T1=V*V,T2=T1*V,T3=V*V*V,T3", - [F1,F2,Lib], S), - ?line eval("T1=V*V, T2=V*V, T1*T2", - [F1,F2,Lib], S), - - ?line {ok, S100} = eval("T0 := E", [E1, E2, E3], S), - ?line {ok, S101} = eval("T1 := E | m1", [E1, E3], S100), - ?line {ok, S102} = eval("T2 := E | m2", [E2], S101), - ?line {{ok, [{user, ['T0', 'T1', 'T2']}]}, _} = xref_base:variables(S102), - ?line {ok, S103} = xref_base:forget(S102, 'T0'), - ?line {{ok, [{user, ['T1', 'T2']}]}, S104} = - xref_base:variables(S103, [user]), - ?line {ok, S105} = xref_base:forget(S104), - ?line {{ok, [{user, []}]}, S106} = xref_base:variables(S105), - ?line {{ok, [{predefined,_}]}, S107_0} = - xref_base:variables(S106, [predefined]), - - ?line {ok, S107_1} = - eval("TT := E, TT2 := V, TT1 := TT * TT", [E1,E2,E3], S107_0), - ?line {{ok, [{user, ['TT', 'TT1', 'TT2']}]}, _} = - xref_base:variables(S107_1), - ?line {ok, S107} = xref_base:forget(S107_1), + S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, + XC_m2, LC_m2), + + S = set_up(S2), + + eval("T1=E, T2=E*T1, T3 = T2*T2, T4=range T3, T5=T3|T4, T5", + [E1,E2,E3], S), + eval("((E*E)*(E*E)) | (range ((E*E)*(E*E)))", + [E1,E2,E3], S), + eval("T1=V*V,T2=T1*V,T3=V*V*V,T3", + [F1,F2,Lib], S), + eval("T1=V*V, T2=V*V, T1*T2", + [F1,F2,Lib], S), + + {ok, S100} = eval("T0 := E", [E1, E2, E3], S), + {ok, S101} = eval("T1 := E | m1", [E1, E3], S100), + {ok, S102} = eval("T2 := E | m2", [E2], S101), + {{ok, [{user, ['T0', 'T1', 'T2']}]}, _} = xref_base:variables(S102), + {ok, S103} = xref_base:forget(S102, 'T0'), + {{ok, [{user, ['T1', 'T2']}]}, S104} = + xref_base:variables(S103, [user]), + {ok, S105} = xref_base:forget(S104), + {{ok, [{user, []}]}, S106} = xref_base:variables(S105), + {{ok, [{predefined,_}]}, S107_0} = + xref_base:variables(S106, [predefined]), + + {ok, S107_1} = + eval("TT := E, TT2 := V, TT1 := TT * TT", [E1,E2,E3], S107_0), + {{ok, [{user, ['TT', 'TT1', 'TT2']}]}, _} = + xref_base:variables(S107_1), + {ok, S107} = xref_base:forget(S107_1), CopyDir = ?copydir, - ?line Dir = fname(CopyDir,"lib_test"), + Dir = fname(CopyDir,"lib_test"), Beam = fname(Dir, "lib1.beam"), - ?line copy_file(fname(Dir, "lib1.erl"), Beam), - ?line {ok, S108} = - xref_base:set_library_path(S107, [Dir], [{verbose,false}]), - ?line {{error, _, _}, _} = xref_base:variables(S108, [{verbose,false}]), - ?line {ok, S109} = xref_base:set_library_path(S108, [], [{verbose,false}]), + copy_file(fname(Dir, "lib1.erl"), Beam), + {ok, S108} = + xref_base:set_library_path(S107, [Dir], [{verbose,false}]), + {{error, _, _}, _} = xref_base:variables(S108, [{verbose,false}]), + {ok, S109} = xref_base:set_library_path(S108, [], [{verbose,false}]), - ?line Tabs = length(ets:all()), + Tabs = length(ets:all()), - ?line {ok, S110} = eval("Eplus := closure E, TT := Eplus", - 'closure()', S109), - ?line {{ok, [{user, ['Eplus','TT']}]}, S111} = xref_base:variables(S110), - ?line {ok, S112} = xref_base:forget(S111, ['TT','Eplus']), - ?line true = Tabs =:= length(ets:all()), + {ok, S110} = eval("Eplus := closure E, TT := Eplus", + 'closure()', S109), + {{ok, [{user, ['Eplus','TT']}]}, S111} = xref_base:variables(S110), + {ok, S112} = xref_base:forget(S111, ['TT','Eplus']), + true = Tabs =:= length(ets:all()), - ?line {ok, NS0} = eval("Eplus := closure E", 'closure()', S112), - ?line {{ok, [{user, ['Eplus']}]}, NS} = xref_base:variables(NS0), - ?line ok = xref_base:delete(NS), - ?line true = Tabs =:= length(ets:all()), + {ok, NS0} = eval("Eplus := closure E", 'closure()', S112), + {{ok, [{user, ['Eplus']}]}, NS} = xref_base:variables(NS0), + ok = xref_base:delete(NS), + true = Tabs =:= length(ets:all()), - ?line ok = file:delete(Beam), + ok = file:delete(Beam), ok. -unused_locals(suite) -> []; -unused_locals(doc) -> ["OTP-5071. Too many unused functions."]; +%% OTP-5071. Too many unused functions. unused_locals(Conf) when is_list(Conf) -> Dir = ?copydir, @@ -2325,8 +2264,8 @@ unused_locals(Conf) when is_list(Conf) -> start(M, F, A) -> spawn(M, F, A). ">>, - ?line ok = file:write_file(File1, Test1), - ?line {ok, a} = compile:file(File1, [debug_info,{outdir,Dir}]), + ok = file:write_file(File1, Test1), + {ok, a} = compile:file(File1, [debug_info,{outdir,Dir}]), File2 = fname(Dir, "b.erl"), MFile2 = fname(Dir, "b"), @@ -2342,123 +2281,109 @@ unused_locals(Conf) when is_list(Conf) -> apply(a, g, [X, Y]). ">>, - ?line ok = file:write_file(File2, Test2), - ?line {ok, b} = compile:file(File2, [debug_info,{outdir,Dir}]), + ok = file:write_file(File2, Test2), + {ok, b} = compile:file(File2, [debug_info,{outdir,Dir}]), - ?line {ok, _} = xref:start(s), - ?line {ok, a} = xref:add_module(s, MFile1), - ?line {ok, b} = xref:add_module(s, MFile2), - ?line {ok, []} = xref:analyse(s, locals_not_used), - ?line ok = check_state(s), - ?line xref:stop(s), + {ok, _} = xref:start(s), + {ok, a} = xref:add_module(s, MFile1), + {ok, b} = xref:add_module(s, MFile2), + {ok, []} = xref:analyse(s, locals_not_used), + ok = check_state(s), + xref:stop(s), - ?line ok = file:delete(File1), - ?line ok = file:delete(Beam1), - ?line ok = file:delete(File2), - ?line ok = file:delete(Beam2), + ok = file:delete(File1), + ok = file:delete(Beam1), + ok = file:delete(File2), + ok = file:delete(Beam2), ok. -format_error(suite) -> []; -format_error(doc) -> ["Format error messages"]; +%% Format error messages format_error(Conf) when is_list(Conf) -> - ?line {ok, _Pid} = start(s), - ?line ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), + {ok, _Pid} = start(s), + ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), %% Parse error messages. - ?line "Invalid regular expression \"add(\"" ++ _ = - fstring(xref:q(s,'"add("')), - ?line 'Invalid operator foo\n' = - fatom(xref:q(s,'foo E')), - ?line 'Invalid wildcard variable \'_Var\' (only \'_\' is allowed)\n' - = fatom(xref:q(s,"module:function/_Var")), - ?line 'Missing type of regular expression ".*"\n' - = fatom(xref:q(s,'".*"')), - ?line 'Type does not match structure of constant: \'M\' : Fun\n' - = fatom(xref:q(s,"'M' : Fun")), - ?line 'Type does not match structure of constant: ".*" : Fun\n' - = fatom(xref:q(s,'".*" : Fun')), - ?line 'Type does not match structure of constant: [m:f/1, m1:f2/3] : App\n' - = fatom(xref:q(s,"[m:f/1,m1:f2/3] : App")), - ?line 'Parse error on line 1: syntax error before: \'-\'\n' = - fatom(xref:q(s,"E + -")), - ?line "Parse error on line 1: unterminated atom starting with 'foo'\n" - = flatten(xref:format_error(xref:q(s,"'foo"))), - ?line 'Parse error at end of string: syntax error before: \n' = - fatom(xref:q(s,"E +")), - ?line 'Parse error on line 1: syntax error before: \'Lin\'\n' = - fatom(xref:q(s,"Lin")), + "Invalid regular expression \"add(\"" ++ _ = fstring(xref:q(s,'"add("')), + 'Invalid operator foo\n' = fatom(xref:q(s,'foo E')), + 'Invalid wildcard variable \'_Var\' (only \'_\' is allowed)\n' + = fatom(xref:q(s,"module:function/_Var")), + 'Missing type of regular expression ".*"\n' + = fatom(xref:q(s,'".*"')), + 'Type does not match structure of constant: \'M\' : Fun\n' + = fatom(xref:q(s,"'M' : Fun")), + 'Type does not match structure of constant: ".*" : Fun\n' + = fatom(xref:q(s,'".*" : Fun')), + 'Type does not match structure of constant: [m:f/1, m1:f2/3] : App\n' + = fatom(xref:q(s,"[m:f/1,m1:f2/3] : App")), + 'Parse error on line 1: syntax error before: \'-\'\n' + = fatom(xref:q(s,"E + -")), + "Parse error on line 1: unterminated atom starting with 'foo'\n" + = flatten(xref:format_error(xref:q(s,"'foo"))), + 'Parse error at end of string: syntax error before: \n' + = fatom(xref:q(s,"E +")), + 'Parse error on line 1: syntax error before: \'Lin\'\n' + = fatom(xref:q(s,"Lin")), %% Other messages - ?line 'Variable \'QQ\' used before set\n' = - fatom(xref:q(s,"QQ")), - ?line 'Unknown constant a\n' = - fatom(xref:q(s,"{a} of E")), + 'Variable \'QQ\' used before set\n' = fatom(xref:q(s,"QQ")), + 'Unknown constant a\n' = fatom(xref:q(s,"{a} of E")), %% Testing xref_parser:t2s/1. - ?line 'Variable assigned more than once: E := E + E\n' = - fatom(xref:q(s,"E:=E + E")), - ?line 'Variable assigned more than once: E = E + E\n' = - fatom(xref:q(s,"E=E + E")), - ?line "Operator applied to argument(s) of different or invalid type(s): " - "E + V * V\n" = - flatten(xref:format_error(xref:q(s,"E + (V * V)"))), - ?line {error,xref_compiler,{type_error,"(V + V) * E"}} = - xref:q(s,"(V + V) * E"), - ?line "Type does not match structure of constant: [m:f/3 -> g:h/17] : " - "App\n" = - flatten(xref:format_error(xref:q(s,"[{{m,f,3},{g,h,17}}] : App"))), - ?line 'Type does not match structure of constant: [m -> f, g -> h] : Fun\n' - = fatom(xref:q(s,"[{m,f},g->h] : Fun")), - ?line 'Type does not match structure of constant: {m, n, o} : Fun\n' = - fatom(xref:q(s,"{m,n,o} : Fun")), - ?line {error,xref_compiler,{type_error,"range (Lin) V"}} = - xref:q(s,"range ((Lin) V)"), - ?line {error,xref_compiler,{type_error,"condensation range E"}} = - xref:q(s,"condensation (range E)"), - ?line {error,xref_compiler,{type_error,"condensation (# E + # V)"}} = - xref:q(s,"condensation (# E + # V)"), - ?line {error,xref_compiler,{type_error,"range (# E + # E)"}} = - xref:q(s,"range (#E + #E)"), - ?line {error,xref_compiler,{type_error,"range (# E)"}} = - xref:q(s,"range #E"), % Hm... - ?line {error,xref_compiler,{type_error,"E + # E"}} = - xref:q(s,"E + #E + #E"), % Hm... - ?line {error,xref_compiler,{type_error,"V * E || V | V"}} = - xref:q(s,"V * (E || V) | V"), - ?line {error,xref_compiler,{type_error,"E || (E | V)"}} = - xref:q(s,"V * E || (E | V)"), - ?line {error,xref_compiler,{type_error,"E * \"m\" : Mod"}} = - xref:q(s,'E * "m" : Mod'), - ?line {error,xref_compiler,{type_error,"E * (\"m\":f/_ + m:\"f\"/3)"}} = - xref:q(s,'E * ("m":f/_ + m:"f"/3)'), - - ?line xref:stop(s), + 'Variable assigned more than once: E := E + E\n' = fatom(xref:q(s,"E:=E + E")), + 'Variable assigned more than once: E = E + E\n' = fatom(xref:q(s,"E=E + E")), + "Operator applied to argument(s) of different or invalid type(s): " + "E + V * V\n" = flatten(xref:format_error(xref:q(s,"E + (V * V)"))), + {error,xref_compiler,{type_error,"(V + V) * E"}} = xref:q(s,"(V + V) * E"), + "Type does not match structure of constant: [m:f/3 -> g:h/17] : " + "App\n" = flatten(xref:format_error(xref:q(s,"[{{m,f,3},{g,h,17}}] : App"))), + 'Type does not match structure of constant: [m -> f, g -> h] : Fun\n' + = fatom(xref:q(s,"[{m,f},g->h] : Fun")), + 'Type does not match structure of constant: {m, n, o} : Fun\n' = + fatom(xref:q(s,"{m,n,o} : Fun")), + {error,xref_compiler,{type_error,"range (Lin) V"}} = + xref:q(s,"range ((Lin) V)"), + {error,xref_compiler,{type_error,"condensation range E"}} = + xref:q(s,"condensation (range E)"), + {error,xref_compiler,{type_error,"condensation (# E + # V)"}} = + xref:q(s,"condensation (# E + # V)"), + {error,xref_compiler,{type_error,"range (# E + # E)"}} = + xref:q(s,"range (#E + #E)"), + {error,xref_compiler,{type_error,"range (# E)"}} = + xref:q(s,"range #E"), % Hm... + {error,xref_compiler,{type_error,"E + # E"}} = + xref:q(s,"E + #E + #E"), % Hm... + {error,xref_compiler,{type_error,"V * E || V | V"}} = + xref:q(s,"V * (E || V) | V"), + {error,xref_compiler,{type_error,"E || (E | V)"}} = + xref:q(s,"V * E || (E | V)"), + {error,xref_compiler,{type_error,"E * \"m\" : Mod"}} = + xref:q(s,'E * "m" : Mod'), + {error,xref_compiler,{type_error,"E * (\"m\":f/_ + m:\"f\"/3)"}} = + xref:q(s,'E * ("m":f/_ + m:"f"/3)'), + + xref:stop(s), ok. -otp_7423(suite) -> []; -otp_7423(doc) -> ["OTP-7423. Xref scanner bug."]; +%% OTP-7423. Xref scanner bug. otp_7423(Conf) when is_list(Conf) -> - ?line {ok, _Pid} = start(s), + {ok, _Pid} = start(s), S = "E | [compiler] : App || [{erlang, size, 1}] : Fun", - ?line {error,xref_compiler,{unknown_constant,"compiler"}} = xref:q(s,S), - ?line xref:stop(s), + {error,xref_compiler,{unknown_constant,"compiler"}} = xref:q(s,S), + xref:stop(s), ok. -otp_7831(suite) -> []; -otp_7831(doc) -> ["OTP-7831. Allow anonymous Xref processes."]; +%% OTP-7831. Allow anonymous Xref processes. otp_7831(Conf) when is_list(Conf) -> - ?line {ok, Pid1} = xref:start([]), - ?line xref:stop(Pid1), - ?line {ok, Pid2} = xref:start([{xref_mode, modules}]), - ?line xref:stop(Pid2), + {ok, Pid1} = xref:start([]), + xref:stop(Pid1), + {ok, Pid2} = xref:start([{xref_mode, modules}]), + xref:stop(Pid2), ok. -otp_10192(suite) -> []; -otp_10192(doc) -> - ["OTP-10192. Allow filenames with character codes greater than 126."]; +%% OTP-10192. Allow filenames with character codes greater than 126. otp_10192(Conf) when is_list(Conf) -> PrivDir = ?privdir, {ok, _Pid} = xref:start(s), @@ -2482,59 +2407,59 @@ fname(Dir, Basename) -> filename:join(Dir, Basename). new() -> - ?line {ok, S} = xref_base:new(), + {ok, S} = xref_base:new(), S. set_up(S) -> - ?line {ok, S1} = xref_base:set_up(S, [{verbose, false}]), + {ok, S1} = xref_base:set_up(S, [{verbose, false}]), S1. eval(Query, E, S) -> ?format("------------------------------~n", []), ?format("Evaluating ~p~n", [Query]), - ?line {Answer, NewState} = xref_base:q(S, Query, [{verbose, false}]), + {Answer, NewState} = xref_base:q(S, Query, [{verbose, false}]), {Reply, Expected} = - case Answer of - {ok, R} when is_list(E) -> - {unsetify(R), sort(E)}; - {ok, R} -> - {unsetify(R), E}; - {error, _Module, Reason} -> - {element(1, Reason), E} - end, + case Answer of + {ok, R} when is_list(E) -> + {unsetify(R), sort(E)}; + {ok, R} -> + {unsetify(R), E}; + {error, _Module, Reason} -> + {element(1, Reason), E} + end, if - Reply =:= Expected -> - ?format("As expected, got ~n~p~n", [Expected]), - {ok, NewState}; - true -> - ?format("Expected ~n~p~nbut got ~n~p~n", [Expected, Reply]), - not_ok + Reply =:= Expected -> + ?format("As expected, got ~n~p~n", [Expected]), + {ok, NewState}; + true -> + ?format("Expected ~n~p~nbut got ~n~p~n", [Expected, Reply]), + not_ok end. analyze(Query, E, S) -> ?format("------------------------------~n", []), ?format("Evaluating ~p~n", [Query]), - ?line {{ok, L}, NewState} = - xref_base:analyze(S, Query, [{verbose, false}]), + {{ok, L}, NewState} = + xref_base:analyze(S, Query, [{verbose, false}]), case {unsetify(L), sort(E)} of - {X,X} -> - ?format("As was expected, got ~n~p~n", [X]), - {ok, NewState}; - {_R,_X} -> - ?format("Expected ~n~p~nbut got ~n~p~n", [_X, _R]), - not_ok + {X,X} -> + ?format("As was expected, got ~n~p~n", [X]), + {ok, NewState}; + {_R,_X} -> + ?format("Expected ~n~p~nbut got ~n~p~n", [_X, _R]), + not_ok end. unsetify(S) -> case is_sofs_set(S) of - true -> to_external(S); - false -> S + true -> to_external(S); + false -> S end. %% Note: assumes S has been set up; the new state is not returned eval(Query, S) -> - ?line {{ok, Answer}, _NewState} = - xref_base:q(S, Query, [{verbose, false}]), + {{ok, Answer}, _NewState} = + xref_base:q(S, Query, [{verbose, false}]), unsetify(Answer). add_module(S, XMod, DefAt, X, LCallAt, XCallAt, XC, LC) -> @@ -2544,159 +2469,159 @@ add_module(S, XMod, DefAt, X, LCallAt, XCallAt, XC, LC) -> Depr = {Depr0,DBad}, Data = {DefAt, LCallAt, XCallAt, LC, XC, X, Attr, Depr}, Unres = [], - ?line {ok, _Module, _Bad, State} = - xref_base:do_add_module(S, XMod, Unres, Data), + {ok, _Module, _Bad, State} = + xref_base:do_add_module(S, XMod, Unres, Data), State. add_application(S, XApp) -> - ?line xref_base:do_add_application(S, XApp). + xref_base:do_add_application(S, XApp). add_release(S, XRel) -> - ?line xref_base:do_add_release(S, XRel). + xref_base:do_add_release(S, XRel). remove_module(S, M) -> - ?line xref_base:do_remove_module(S, M). + xref_base:do_remove_module(S, M). info_tag(Info, Tag) -> {value, {_Tag, Value}} = lists:keysearch(Tag, 1, Info), Value. make_ufile(FileName) -> - ?line ok = file:write_file(FileName, term_to_binary(foo)), - ?line hide_file(FileName). + ok = file:write_file(FileName, term_to_binary(foo)), + hide_file(FileName). make_udir(Dir) -> - ?line ok = file:make_dir(Dir), - ?line hide_file(Dir). + ok = file:make_dir(Dir), + hide_file(Dir). hide_file(FileName) -> - ?line {ok, FileInfo} = file:read_file_info(FileName), - ?line NewFileInfo = FileInfo#file_info{mode = 0}, - ?line ok = file:write_file_info(FileName, NewFileInfo). + {ok, FileInfo} = file:read_file_info(FileName), + NewFileInfo = FileInfo#file_info{mode = 0}, + ok = file:write_file_info(FileName, NewFileInfo). %% Note that S has to be set up before calling this checking function. check_state(S) -> - ?line Info = xref:info(S), + Info = xref:info(S), - ?line modules_mode_check(S, Info), + modules_mode_check(S, Info), case info(Info, mode) of - modules -> - ok; - functions -> - functions_mode_check(S, Info) + modules -> + ok; + functions -> + functions_mode_check(S, Info) end. %% The manual mentions some facts that should always hold. %% Here they are again. functions_mode_check(S, Info) -> %% F = L + X, - ?line {ok, F} = xref:q(S, "F"), - ?line {ok, F} = xref:q(S, "L + X"), + {ok, F} = xref:q(S, "F"), + {ok, F} = xref:q(S, "L + X"), %% V = X + L + B + U, - ?line {ok, V} = xref:q(S, "V"), - ?line {ok, V} = xref:q(S, "X + L + B + U"), + {ok, V} = xref:q(S, "V"), + {ok, V} = xref:q(S, "X + L + B + U"), %% X, L, B and U are disjoint. - ?line {ok, []} = - xref:q(S, "X * L + X * B + X * U + L * B + L * U + B * U"), + {ok, []} = + xref:q(S, "X * L + X * B + X * U + L * B + L * U + B * U"), %% V = UU + XU + LU, - ?line {ok, V} = xref:q(S, "UU + XU + LU"), + {ok, V} = xref:q(S, "UU + XU + LU"), %% E = LC + XC - ?line {ok, E} = xref:q(S, "E"), - ?line {ok, E} = xref:q(S, "LC + XC"), + {ok, E} = xref:q(S, "E"), + {ok, E} = xref:q(S, "LC + XC"), %% U subset of XU, - ?line {ok, []} = xref:q(S, "U - XU"), + {ok, []} = xref:q(S, "U - XU"), %% LU = range LC - ?line {ok, []} = xref:q(S, "(LU - range LC) + (range LC - LU)"), + {ok, []} = xref:q(S, "(LU - range LC) + (range LC - LU)"), %% XU = range XC - ?line {ok, []} = xref:q(S, "(XU - range XC) + (range XC - XU)"), + {ok, []} = xref:q(S, "(XU - range XC) + (range XC - XU)"), %% LU subset F - ?line {ok, []} = xref:q(S, "LU - F"), + {ok, []} = xref:q(S, "LU - F"), %% UU subset F - ?line {ok, []} = xref:q(S, "UU - F"), + {ok, []} = xref:q(S, "UU - F"), %% ME = (Mod) E - ?line {ok, ME} = xref:q(S, "ME"), - ?line {ok, ME} = xref:q(S, "(Mod) E"), + {ok, ME} = xref:q(S, "ME"), + {ok, ME} = xref:q(S, "(Mod) E"), %% AE = (App) E - ?line {ok, AE} = xref:q(S, "AE"), - ?line {ok, AE} = xref:q(S, "(App) E"), + {ok, AE} = xref:q(S, "AE"), + {ok, AE} = xref:q(S, "(App) E"), %% RE = (Rel) E - ?line {ok, RE} = xref:q(S, "RE"), - ?line {ok, RE} = xref:q(S, "(Rel) E"), + {ok, RE} = xref:q(S, "RE"), + {ok, RE} = xref:q(S, "(Rel) E"), %% (Mod) V subset of M - ?line {ok, []} = xref:q(S, "(Mod) V - M"), + {ok, []} = xref:q(S, "(Mod) V - M"), %% range UC subset of U - ?line {ok, []} = xref:q(S, "range UC - U"), + {ok, []} = xref:q(S, "range UC - U"), %% Some checks on the numbers returned by the info functions. - ?line {Resolved, Unresolved} = info(Info, no_calls), - ?line AllCalls = Resolved + Unresolved, - ?line {ok, AllCalls} = xref:q(S, "# (XLin) E + # (LLin) E"), + {Resolved, Unresolved} = info(Info, no_calls), + AllCalls = Resolved + Unresolved, + {ok, AllCalls} = xref:q(S, "# (XLin) E + # (LLin) E"), - ?line {Local, Exported} = info(Info, no_functions), - ?line LX = Local+Exported, - ?line {ok, LXs} = xref:q(S, 'Extra = _:module_info/"(0|1)" + LM, - # (F - Extra)'), - ?line true = LX =:= LXs, + {Local, Exported} = info(Info, no_functions), + LX = Local+Exported, + {ok, LXs} = xref:q(S, 'Extra = _:module_info/"(0|1)" + LM, + # (F - Extra)'), + true = LX =:= LXs, - ?line {LocalCalls, ExternalCalls, UnresCalls} = - info(Info, no_function_calls), - ?line LEU = LocalCalls + ExternalCalls + UnresCalls, - ?line {ok, LEU} = xref:q(S, "# LC + # XC"), + {LocalCalls, ExternalCalls, UnresCalls} = + info(Info, no_function_calls), + LEU = LocalCalls + ExternalCalls + UnresCalls, + {ok, LEU} = xref:q(S, "# LC + # XC"), - ?line InterFunctionCalls = info(Info, no_inter_function_calls), - ?line {ok, InterFunctionCalls} = xref:q(S, "# EE"), + InterFunctionCalls = info(Info, no_inter_function_calls), + {ok, InterFunctionCalls} = xref:q(S, "# EE"), %% And some more checks on counters... - ?line check_count(S), + check_count(S), %% ... and more - ?line {ok, []} = xref:q(S, "LM - X - U - B"), + {ok, []} = xref:q(S, "LM - X - U - B"), ok. modules_mode_check(S, Info) -> %% B subset of XU, - ?line {ok, []} = xref:q(S, "B - XU"), + {ok, []} = xref:q(S, "B - XU"), %% M = AM + LM + UM - ?line {ok, M} = xref:q(S, "M"), - ?line {ok, M} = xref:q(S, "AM + LM + UM"), + {ok, M} = xref:q(S, "M"), + {ok, M} = xref:q(S, "AM + LM + UM"), %% DF is a subset of X U B, etc. - ?line {ok, []} = xref:q(S, "DF - X - B"), - ?line {ok, []} = xref:q(S, "DF_3 - DF"), - ?line {ok, []} = xref:q(S, "DF_2 - DF_3"), - ?line {ok, []} = xref:q(S, "DF_1 - DF_2"), + {ok, []} = xref:q(S, "DF - X - B"), + {ok, []} = xref:q(S, "DF_3 - DF"), + {ok, []} = xref:q(S, "DF_2 - DF_3"), + {ok, []} = xref:q(S, "DF_1 - DF_2"), %% AM, LM and UM are disjoint. - ?line {ok, []} = xref:q(S, "AM * LM + AM * UM + LM * UM"), + {ok, []} = xref:q(S, "AM * LM + AM * UM + LM * UM"), %% (App) M subset of A - ?line {ok, []} = xref:q(S, "(App) M - A"), + {ok, []} = xref:q(S, "(App) M - A"), - ?line AM = info(Info, no_analyzed_modules), - ?line {ok, AM} = xref:q(S, "# AM"), + AM = info(Info, no_analyzed_modules), + {ok, AM} = xref:q(S, "# AM"), - ?line A = info(Info, no_applications), - ?line {ok, A} = xref:q(S, "# A"), + A = info(Info, no_applications), + {ok, A} = xref:q(S, "# A"), - ?line NoR = info(Info, no_releases), - ?line {ok, NoR} = xref:q(S, "# R"), + NoR = info(Info, no_releases), + {ok, NoR} = xref:q(S, "# R"), ok. @@ -2708,7 +2633,7 @@ check_count(S) -> {ok, M} = xref:q(S, 'AM'), {ok, _} = xref:q(S, - "Extra := _:module_info/\"(0|1)\" + LM"), + "Extra := _:module_info/\"(0|1)\" + LM"), %% info/1: {ok, NoR} = xref:q(S, '# R'), @@ -2743,7 +2668,7 @@ check_count(S) -> info_module([M | Ms], S) -> {ok, NoCalls} = per_module("T = (E | ~p : Mod), # (XLin) T + # (LLin) T", - M, S), + M, S), {ok, NoFunCalls} = per_module("# (E | ~p : Mod)", M, S), {ok, NoXCalls} = per_module("# (XC | ~p : Mod)", M, S), {ok, NoLCalls} = per_module("# (LC | ~p : Mod)", M, S), @@ -2783,40 +2708,38 @@ fstring(R) -> flatten(xref:format_error(R)). start(Server) -> - ?line case xref:start(Server) of - {error, {already_started, _Pid}} -> - ?line xref:stop(Server), - ?line xref:start(Server); - R -> R - end. + case xref:start(Server) of + {error, {already_started, _Pid}} -> + xref:stop(Server), + xref:start(Server); + R -> R + end. add_erts_code_path(KernelPath) -> VersionDirs = - filelib:is_dir( - filename:join( - [code:lib_dir(), - lists:flatten( - ["kernel-", - [X || - {kernel,_,X} <- - application_controller:which_applications()]])])), + filelib:is_dir( + filename:join( + [code:lib_dir(), + lists:flatten( + ["kernel-", + [X || + {kernel,_,X} <- + application_controller:which_applications()]])])), case VersionDirs of - true -> - case code:lib_dir(erts) of - String when is_list(String) -> - [KernelPath, fname(String,"ebin")]; - _Other1 -> - [KernelPath] - end; - false -> - % Clearcase? - PrelPath = filename:join([code:lib_dir(),"..","erts","preloaded"]), - case filelib:is_dir(PrelPath) of - true -> - [KernelPath, fname(PrelPath,"ebin")]; - false -> - [KernelPath] - end + true -> + case code:lib_dir(erts) of + String when is_list(String) -> + [KernelPath, fname(String,"ebin")]; + _Other1 -> + [KernelPath] + end; + false -> + % Clearcase? + PrelPath = filename:join([code:lib_dir(),"..","erts","preloaded"]), + case filelib:is_dir(PrelPath) of + true -> + [KernelPath, fname(PrelPath,"ebin")]; + false -> + [KernelPath] + end end. - - diff --git a/lib/tools/vsn.mk b/lib/tools/vsn.mk index 3b3202d38b..70564f05c6 100644 --- a/lib/tools/vsn.mk +++ b/lib/tools/vsn.mk @@ -1 +1 @@ -TOOLS_VSN = 2.7.2 +TOOLS_VSN = 2.8.3 |