diff --git a/jbmc/src/jbmc/jbmc_parse_options.cpp b/jbmc/src/jbmc/jbmc_parse_options.cpp index 4ab56be7ee1..1ae451e1180 100644 --- a/jbmc/src/jbmc/jbmc_parse_options.cpp +++ b/jbmc/src/jbmc/jbmc_parse_options.cpp @@ -461,7 +461,7 @@ int jbmc_parse_optionst::doit() break; case ui_message_handlert::uit::JSON_UI: { - json_objectt json_options({{"options", options.to_json()}}); + json_objectt json_options{{"options", options.to_json()}}; debug() << json_options; break; } diff --git a/src/analyses/ai.cpp b/src/analyses/ai.cpp index d20c0c4ebbe..e6ffe288695 100644 --- a/src/analyses/ai.cpp +++ b/src/analyses/ai.cpp @@ -95,11 +95,11 @@ jsont ai_baset::output_json( std::ostringstream out; goto_program.output_instruction(ns, function_id, out, *i_it); - json_objectt location( - {{"locationNumber", json_numbert(std::to_string(i_it->location_number))}, - {"sourceLocation", json_stringt(i_it->source_location.as_string())}, - {"abstractState", abstract_state_before(i_it)->output_json(*this, ns)}, - {"instruction", json_stringt(out.str())}}); + json_objectt location{ + {"locationNumber", json_numbert(std::to_string(i_it->location_number))}, + {"sourceLocation", json_stringt(i_it->source_location.as_string())}, + {"abstractState", abstract_state_before(i_it)->output_json(*this, ns)}, + {"instruction", json_stringt(out.str())}}; contents.push_back(std::move(location)); } diff --git a/src/analyses/dependence_graph.cpp b/src/analyses/dependence_graph.cpp index e4c5a8c25c6..d80ad819256 100644 --- a/src/analyses/dependence_graph.cpp +++ b/src/analyses/dependence_graph.cpp @@ -285,19 +285,19 @@ jsont dep_graph_domaint::output_json( for(const auto &cd : control_deps) { - json_objectt link( - {{"locationNumber", json_numbert(std::to_string(cd->location_number))}, - {"sourceLocation", json(cd->source_location)}, - {"type", json_stringt("control")}}); + json_objectt link{ + {"locationNumber", json_numbert(std::to_string(cd->location_number))}, + {"sourceLocation", json(cd->source_location)}, + {"type", json_stringt("control")}}; graph.push_back(std::move(link)); } for(const auto &dd : data_deps) { - json_objectt link( - {{"locationNumber", json_numbert(std::to_string(dd->location_number))}, - {"sourceLocation", json(dd->source_location)}, - {"type", json_stringt("data")}}); + json_objectt link{ + {"locationNumber", json_numbert(std::to_string(dd->location_number))}, + {"sourceLocation", json(dd->source_location)}, + {"type", json_stringt("data")}}; graph.push_back(std::move(link)); } diff --git a/src/cbmc/bmc_cover.cpp b/src/cbmc/bmc_cover.cpp index 8e84935c3c1..143fd922acd 100644 --- a/src/cbmc/bmc_cover.cpp +++ b/src/cbmc/bmc_cover.cpp @@ -383,7 +383,7 @@ bool bmc_covert::operator()() { if(step.is_input()) { - json_objectt json_input({{"id", json_stringt(step.io_id)}}); + json_objectt json_input{{"id", json_stringt(step.io_id)}}; if(step.io_args.size()==1) json_input["value"]= json(step.io_args.front(), bmc.ns, ID_unknown); diff --git a/src/goto-analyzer/static_verifier.cpp b/src/goto-analyzer/static_verifier.cpp index 305ce3dcf24..83af3edba94 100644 --- a/src/goto-analyzer/static_verifier.cpp +++ b/src/goto-analyzer/static_verifier.cpp @@ -12,6 +12,7 @@ Author: Martin Brain, martin.brain@cs.ox.ac.uk #include #include #include +#include #include @@ -20,48 +21,42 @@ Author: Martin Brain, martin.brain@cs.ox.ac.uk struct static_verifier_resultt { // clang-format off - enum { TRUE, FALSE, BOTTOM, UNKNOWN } status; + enum statust { TRUE, FALSE, BOTTOM, UNKNOWN } status; // clang-format on source_locationt source_location; irep_idt function_id; }; +/// Makes a status message string from a status. +static const char *message(const static_verifier_resultt::statust &status) +{ + switch(status) + { + case static_verifier_resultt::TRUE: + return "SUCCESS"; + case static_verifier_resultt::FALSE: + return "FAILURE (if reachable)"; + case static_verifier_resultt::BOTTOM: + return "SUCCESS (unreachable)"; + case static_verifier_resultt::UNKNOWN: + return "UNKNOWN"; + } + UNREACHABLE; +} + static void static_verifier_json( const std::vector &results, messaget &m, std::ostream &out) { m.status() << "Writing JSON report" << messaget::eom; - - json_arrayt json_result; - - for(const auto &result : results) - { - json_objectt &j = json_result.push_back().make_object(); - - switch(result.status) - { - case static_verifier_resultt::TRUE: - j["status"] = json_stringt("SUCCESS"); - break; - - case static_verifier_resultt::FALSE: - j["status"] = json_stringt("FAILURE (if reachable)"); - break; - - case static_verifier_resultt::BOTTOM: - j["status"] = json_stringt("SUCCESS (unreachable)"); - break; - - case static_verifier_resultt::UNKNOWN: - j["status"] = json_stringt("UNKNOWN"); - break; - } - - j["sourceLocation"] = json(result.source_location); - } - - out << json_result; + out << make_range(results) + .map([](const static_verifier_resultt &result) { + return json_objectt{ + {"status", json_stringt{message(result.status)}}, + {"sourceLocation", json(result.source_location)}}; + }) + .collect(); } static void static_verifier_xml( diff --git a/src/goto-analyzer/taint_analysis.cpp b/src/goto-analyzer/taint_analysis.cpp index fcd104b37d1..d65f562c86c 100644 --- a/src/goto-analyzer/taint_analysis.cpp +++ b/src/goto-analyzer/taint_analysis.cpp @@ -355,12 +355,12 @@ bool taint_analysist::operator()( if(use_json) { - json_objectt json( - {{"bugClass", - json_stringt(i_it->source_location.get_property_class())}, - {"file", json_stringt(i_it->source_location.get_file())}, - {"line", - json_numbert(id2string(i_it->source_location.get_line()))}}); + json_objectt json{ + {"bugClass", + json_stringt(i_it->source_location.get_property_class())}, + {"file", json_stringt(i_it->source_location.get_file())}, + {"line", + json_numbert(id2string(i_it->source_location.get_line()))}}; json_result.push_back(std::move(json)); } else diff --git a/src/goto-analyzer/unreachable_instructions.cpp b/src/goto-analyzer/unreachable_instructions.cpp index b5c068e0ae9..a28834f7695 100644 --- a/src/goto-analyzer/unreachable_instructions.cpp +++ b/src/goto-analyzer/unreachable_instructions.cpp @@ -114,12 +114,12 @@ static void add_to_json( DATA_INVARIANT(end_function->is_end_function(), "The last instruction in a goto-program must be END_FUNCTION"); - json_objectt entry( - {{"function", json_stringt(function_identifier)}, - {"fileName", - json_stringt(concat_dir_file( - id2string(end_function->source_location.get_working_directory()), - id2string(end_function->source_location.get_file())))}}); + json_objectt entry{ + {"function", json_stringt(function_identifier)}, + {"fileName", + json_stringt(concat_dir_file( + id2string(end_function->source_location.get_working_directory()), + id2string(end_function->source_location.get_file())))}}; json_arrayt &dead_ins=entry["unreachableInstructions"].make_array(); @@ -142,8 +142,8 @@ static void add_to_json( // print info for file actually with full path const source_locationt &l=it->second->source_location; - json_objectt i_entry( - {{"sourceLocation", json(l)}, {"statement", json_stringt(s)}}); + json_objectt i_entry{{"sourceLocation", json(l)}, + {"statement", json_stringt(s)}}; dead_ins.push_back(std::move(i_entry)); } @@ -246,14 +246,14 @@ static void json_output_function( const source_locationt &last_location, json_arrayt &dest) { - json_objectt entry( - {{"function", json_stringt(function)}, - {"file name", - json_stringt(concat_dir_file( - id2string(first_location.get_working_directory()), - id2string(first_location.get_file())))}, - {"first line", json_numbert(id2string(first_location.get_line()))}, - {"last line", json_numbert(id2string(last_location.get_line()))}}); + json_objectt entry{ + {"function", json_stringt(function)}, + {"file name", + json_stringt(concat_dir_file( + id2string(first_location.get_working_directory()), + id2string(first_location.get_file())))}, + {"first line", json_numbert(id2string(first_location.get_line()))}, + {"last line", json_numbert(id2string(last_location.get_line()))}}; dest.push_back(std::move(entry)); } diff --git a/src/goto-diff/goto_diff_base.cpp b/src/goto-diff/goto_diff_base.cpp index e76e4abe300..e469216ced9 100644 --- a/src/goto-diff/goto_diff_base.cpp +++ b/src/goto-diff/goto_diff_base.cpp @@ -38,9 +38,9 @@ void goto_difft::output_functions() const } case ui_message_handlert::uit::JSON_UI: { - json_objectt json_result( - {{"totalNumberOfFunctions", - json_stringt(std::to_string(total_functions_count))}}); + json_objectt json_result{ + {"totalNumberOfFunctions", + json_stringt(std::to_string(total_functions_count))}}; convert_function_group_json( json_result["newFunctions"].make_array(), new_functions, goto_model2); convert_function_group_json( diff --git a/src/goto-instrument/unwind.cpp b/src/goto-instrument/unwind.cpp index ced24975192..b846be2fa93 100644 --- a/src/goto-instrument/unwind.cpp +++ b/src/goto-instrument/unwind.cpp @@ -346,11 +346,10 @@ jsont goto_unwindt::unwind_logt::output_log_json() const goto_programt::const_targett target=it->first; unsigned location_number=it->second; - json_objectt object( - {{"originalLocationNumber", - json_numbert(std::to_string(location_number))}, - {"newLocationNumber", - json_numbert(std::to_string(target->location_number))}}); + json_objectt object{ + {"originalLocationNumber", json_numbert(std::to_string(location_number))}, + {"newLocationNumber", + json_numbert(std::to_string(target->location_number))}}; json_unwound.push_back(std::move(object)); } diff --git a/src/goto-programs/goto_inline_class.cpp b/src/goto-programs/goto_inline_class.cpp index 62cb5c1b9d2..454430cdc69 100644 --- a/src/goto-programs/goto_inline_class.cpp +++ b/src/goto-programs/goto_inline_class.cpp @@ -887,17 +887,17 @@ jsont goto_inlinet::goto_inline_logt::output_inline_log_json() const PRECONDITION(start->location_number <= end->location_number); - json_arrayt json_orig( - {json_numbert(std::to_string(info.begin_location_number)), - json_numbert(std::to_string(info.end_location_number))}); - json_arrayt json_new({json_numbert(std::to_string(start->location_number)), - json_numbert(std::to_string(end->location_number))}); - - json_objectt object( - {{"call", json_numbert(std::to_string(info.call_location_number))}, - {"function", json_stringt(info.function.c_str())}, - {"originalSegment", std::move(json_orig)}, - {"inlinedSegment", std::move(json_new)}}); + json_arrayt json_orig{ + json_numbert(std::to_string(info.begin_location_number)), + json_numbert(std::to_string(info.end_location_number))}; + json_arrayt json_new{json_numbert(std::to_string(start->location_number)), + json_numbert(std::to_string(end->location_number))}; + + json_objectt object{ + {"call", json_numbert(std::to_string(info.call_location_number))}, + {"function", json_stringt(info.function.c_str())}, + {"originalSegment", std::move(json_orig)}, + {"inlinedSegment", std::move(json_new)}}; json_inlined.push_back(std::move(object)); } diff --git a/src/goto-programs/json_expr.cpp b/src/goto-programs/json_expr.cpp index 5e213c59b1b..e0938a9356f 100644 --- a/src/goto-programs/json_expr.cpp +++ b/src/goto-programs/json_expr.cpp @@ -172,8 +172,8 @@ json_objectt json(const typet &type, const namespacet &ns, const irep_idt &mode) to_struct_type(type).components(); for(const auto &component : components) { - json_objectt e({{"name", json_stringt(component.get_name())}, - {"type", json(component.type(), ns, mode)}}); + json_objectt e{{"name", json_stringt(component.get_name())}, + {"type", json(component.type(), ns, mode)}}; members.push_back(std::move(e)); } } @@ -185,8 +185,8 @@ json_objectt json(const typet &type, const namespacet &ns, const irep_idt &mode) to_union_type(type).components(); for(const auto &component : components) { - json_objectt e({{"name", json_stringt(component.get_name())}, - {"type", json(component.type(), ns, mode)}}); + json_objectt e{{"name", json_stringt(component.get_name())}, + {"type", json(component.type(), ns, mode)}}; members.push_back(std::move(e)); } } @@ -348,8 +348,8 @@ json_objectt json(const exprt &expr, const namespacet &ns, const irep_idt &mode) forall_operands(it, expr) { - json_objectt e({{"index", json_numbert(std::to_string(index))}, - {"value", json(*it, ns, mode)}}); + json_objectt e{{"index", json_numbert(std::to_string(index))}, + {"value", json(*it, ns, mode)}}; elements.push_back(std::move(e)); index++; } @@ -370,8 +370,8 @@ json_objectt json(const exprt &expr, const namespacet &ns, const irep_idt &mode) json_arrayt &members = result["members"].make_array(); for(std::size_t m = 0; m < expr.operands().size(); m++) { - json_objectt e({{"value", json(expr.operands()[m], ns, mode)}, - {"name", json_stringt(components[m].get_name())}}); + json_objectt e{{"value", json(expr.operands()[m], ns, mode)}, + {"name", json_stringt(components[m].get_name())}}; members.push_back(std::move(e)); } } diff --git a/src/goto-programs/show_goto_functions_json.cpp b/src/goto-programs/show_goto_functions_json.cpp index da73e785eb9..9c3e77adb7f 100644 --- a/src/goto-programs/show_goto_functions_json.cpp +++ b/src/goto-programs/show_goto_functions_json.cpp @@ -70,8 +70,8 @@ json_objectt show_goto_functions_jsont::convert( for(const goto_programt::instructiont &instruction : function.body.instructions) { - json_objectt instruction_entry( - {{"instructionId", json_stringt(instruction.to_string())}}); + json_objectt instruction_entry{ + {"instructionId", json_stringt(instruction.to_string())}}; if(instruction.code.source_location().is_not_nil()) { diff --git a/src/goto-programs/show_properties.cpp b/src/goto-programs/show_properties.cpp index 75af9ba0252..f5f4da55af2 100644 --- a/src/goto-programs/show_properties.cpp +++ b/src/goto-programs/show_properties.cpp @@ -129,12 +129,12 @@ void convert_properties_json( irep_idt property_id=source_location.get_property_id(); - json_objectt json_property( - {{"name", json_stringt(property_id)}, - {"class", json_stringt(property_class)}, - {"sourceLocation", json(source_location)}, - {"description", json_stringt(description)}, - {"expression", json_stringt(from_expr(ns, identifier, ins.guard))}}); + json_objectt json_property{ + {"name", json_stringt(property_id)}, + {"class", json_stringt(property_class)}, + {"sourceLocation", json(source_location)}, + {"description", json_stringt(description)}, + {"expression", json_stringt(from_expr(ns, identifier, ins.guard))}}; if(!source_location.get_basic_block_covered_lines().empty()) json_property["coveredLines"] = @@ -155,7 +155,7 @@ void show_properties_json( for(const auto &fct : goto_functions.function_map) convert_properties_json(json_properties, ns, fct.first, fct.second.body); - json_objectt json_result({{"properties", json_properties}}); + json_objectt json_result{{"properties", json_properties}}; msg.result() << json_result; } diff --git a/src/goto-programs/show_symbol_table.cpp b/src/goto-programs/show_symbol_table.cpp index e64eb0b3ab5..509904cd3ea 100644 --- a/src/goto-programs/show_symbol_table.cpp +++ b/src/goto-programs/show_symbol_table.cpp @@ -194,36 +194,36 @@ static void show_symbol_table_json_ui( if(symbol.value.is_not_nil()) ptr->from_expr(symbol.value, value_str, ns); - json_objectt symbol_json( - {{"prettyName", json_stringt(symbol.pretty_name)}, - {"name", json_stringt(symbol.name)}, - {"baseName", json_stringt(symbol.base_name)}, - {"mode", json_stringt(symbol.mode)}, - {"module", json_stringt(symbol.module)}, - - {"prettyType", json_stringt(type_str)}, - {"prettyValue", json_stringt(value_str)}, - - {"type", irep_converter.convert_from_irep(symbol.type)}, - {"value", irep_converter.convert_from_irep(symbol.value)}, - {"location", irep_converter.convert_from_irep(symbol.location)}, - - {"isType", jsont::json_boolean(symbol.is_type)}, - {"isMacro", jsont::json_boolean(symbol.is_macro)}, - {"isExported", jsont::json_boolean(symbol.is_exported)}, - {"isInput", jsont::json_boolean(symbol.is_input)}, - {"isOutput", jsont::json_boolean(symbol.is_output)}, - {"isStateVar", jsont::json_boolean(symbol.is_state_var)}, - {"isProperty", jsont::json_boolean(symbol.is_property)}, - {"isStaticLifetime", jsont::json_boolean(symbol.is_static_lifetime)}, - {"isThreadLocal", jsont::json_boolean(symbol.is_thread_local)}, - {"isLvalue", jsont::json_boolean(symbol.is_lvalue)}, - {"isFileLocal", jsont::json_boolean(symbol.is_file_local)}, - {"isExtern", jsont::json_boolean(symbol.is_extern)}, - {"isVolatile", jsont::json_boolean(symbol.is_volatile)}, - {"isParameter", jsont::json_boolean(symbol.is_parameter)}, - {"isAuxiliary", jsont::json_boolean(symbol.is_auxiliary)}, - {"isWeak", jsont::json_boolean(symbol.is_weak)}}); + json_objectt symbol_json{ + {"prettyName", json_stringt(symbol.pretty_name)}, + {"name", json_stringt(symbol.name)}, + {"baseName", json_stringt(symbol.base_name)}, + {"mode", json_stringt(symbol.mode)}, + {"module", json_stringt(symbol.module)}, + + {"prettyType", json_stringt(type_str)}, + {"prettyValue", json_stringt(value_str)}, + + {"type", irep_converter.convert_from_irep(symbol.type)}, + {"value", irep_converter.convert_from_irep(symbol.value)}, + {"location", irep_converter.convert_from_irep(symbol.location)}, + + {"isType", jsont::json_boolean(symbol.is_type)}, + {"isMacro", jsont::json_boolean(symbol.is_macro)}, + {"isExported", jsont::json_boolean(symbol.is_exported)}, + {"isInput", jsont::json_boolean(symbol.is_input)}, + {"isOutput", jsont::json_boolean(symbol.is_output)}, + {"isStateVar", jsont::json_boolean(symbol.is_state_var)}, + {"isProperty", jsont::json_boolean(symbol.is_property)}, + {"isStaticLifetime", jsont::json_boolean(symbol.is_static_lifetime)}, + {"isThreadLocal", jsont::json_boolean(symbol.is_thread_local)}, + {"isLvalue", jsont::json_boolean(symbol.is_lvalue)}, + {"isFileLocal", jsont::json_boolean(symbol.is_file_local)}, + {"isExtern", jsont::json_boolean(symbol.is_extern)}, + {"isVolatile", jsont::json_boolean(symbol.is_volatile)}, + {"isParameter", jsont::json_boolean(symbol.is_parameter)}, + {"isAuxiliary", jsont::json_boolean(symbol.is_auxiliary)}, + {"isWeak", jsont::json_boolean(symbol.is_weak)}}; result.push_back(id2string(symbol.name), std::move(symbol_json)); } @@ -265,15 +265,15 @@ static void show_symbol_table_brief_json_ui( if(symbol.type.is_not_nil()) ptr->from_type(symbol.type, type_str, ns); - json_objectt symbol_json( - {{"prettyName", json_stringt(symbol.pretty_name)}, - {"baseName", json_stringt(symbol.base_name)}, - {"mode", json_stringt(symbol.mode)}, - {"module", json_stringt(symbol.module)}, + json_objectt symbol_json{ + {"prettyName", json_stringt(symbol.pretty_name)}, + {"baseName", json_stringt(symbol.base_name)}, + {"mode", json_stringt(symbol.mode)}, + {"module", json_stringt(symbol.module)}, - {"prettyType", json_stringt(type_str)}, + {"prettyType", json_stringt(type_str)}, - {"type", irep_converter.convert_from_irep(symbol.type)}}); + {"type", irep_converter.convert_from_irep(symbol.type)}}; result.push_back(id2string(symbol.name), std::move(symbol_json)); } diff --git a/src/util/constructor_of.h b/src/util/constructor_of.h new file mode 100644 index 00000000000..71a7bd874fa --- /dev/null +++ b/src/util/constructor_of.h @@ -0,0 +1,35 @@ +/*******************************************************************\ + +Module: constructor_of + +Author: Diffblue Ltd. + +\*******************************************************************/ + +#ifndef CPROVER_UTIL_CONSTRUCTOR_OF_H +#define CPROVER_UTIL_CONSTRUCTOR_OF_H + +#include + +/// A type of functor which wraps around the set of constructors of a type. +/// \tparam constructedt: The type which this functor constructs. +template +class constructor_oft final +{ +public: + template + constructedt operator()(argumentst &&... arguments) + { + return constructedt{std::forward(arguments)...}; + } +}; + +/// \tparam constructedt: A type for construction. +/// \brief Returns a functor which constructs type `constructedt`. +template +constexpr constructor_oft constructor_of() +{ + return {}; +} + +#endif // CPROVER_UTIL_CONSTRUCTOR_OF_H diff --git a/src/util/json.h b/src/util/json.h index 4e5d3831902..529b13a8ddd 100644 --- a/src/util/json.h +++ b/src/util/json.h @@ -16,6 +16,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include "irep.h" +#include "range.h" class json_objectt; class json_arrayt; @@ -160,8 +161,29 @@ class json_arrayt:public jsont { } - explicit json_arrayt(arrayt &&entries) - : jsont(kindt::J_ARRAY, std::move(entries)) + explicit json_arrayt(std::initializer_list &&initializer_list) + : jsont(kindt::J_ARRAY, arrayt{initializer_list}) + { + } + + template + json_arrayt(begin_iteratort &&begin_iterator, end_iteratort &&end_iterator) + : jsont( + kindt::J_ARRAY, + arrayt( + std::forward(begin_iterator), + std::forward(end_iterator))) + { + static_assert( + std::is_same< + typename std::decay::type, + typename std::decay::type>::value, + "The iterators must be of the same type."); + } + + template + explicit json_arrayt(ranget &&range) + : jsont(kindt::J_ARRAY, arrayt{range.begin(), range.end()}) { } @@ -278,8 +300,30 @@ class json_objectt:public jsont { } - explicit json_objectt(objectt &&objects) - : jsont(kindt::J_OBJECT, std::move(objects)) + explicit json_objectt( + std::initializer_list &&initializer_list) + : jsont(kindt::J_OBJECT, objectt{initializer_list}) + { + } + + template + json_objectt(begin_iteratort &&begin_iterator, end_iteratort &&end_iterator) + : jsont( + kindt::J_OBJECT, + objectt( + std::forward(begin_iterator), + std::forward(end_iterator))) + { + static_assert( + std::is_same< + typename std::decay::type, + typename std::decay::type>::value, + "The iterators must be of the same type."); + } + + template + explicit json_objectt(ranget &&range) + : jsont(kindt::J_OBJECT, objectt{range.begin(), range.end()}) { } diff --git a/src/util/options.cpp b/src/util/options.cpp index c75a02182c1..aa73c45b9ba 100644 --- a/src/util/options.cpp +++ b/src/util/options.cpp @@ -11,7 +11,9 @@ Author: Daniel Kroening, kroening@kroening.com #include "options.h" +#include "constructor_of.h" #include "json.h" +#include "range.h" #include "string2int.h" #include "xml.h" @@ -90,14 +92,12 @@ const optionst::value_listt &optionst::get_list_option( /// Returns the options as JSON key value pairs json_objectt optionst::to_json() const { - json_objectt json_options; - for(const auto &option_pair : option_map) - { - json_arrayt &values = json_options[option_pair.first].make_array(); - for(const auto &value : option_pair.second) - values.push_back(json_stringt(value)); - } - return json_options; + return make_range(option_map) + .map([](const std::pair &option_pair) { + return std::pair{ + option_pair.first, + make_range(option_pair.second).map(constructor_of())}; + }); } /// Returns the options in XML format diff --git a/src/util/range.h b/src/util/range.h index 0f91cbdabc1..770bc6d1398 100644 --- a/src/util/range.h +++ b/src/util/range.h @@ -351,6 +351,20 @@ struct ranget final return end_value; } + /// Constructs a collection containing the values, which this range iterates + /// over. + template + containert collect() const + { + return containert(begin(), end()); + } + + template + operator containert() const + { + return collect(); + } + private: iteratort begin_value; iteratort end_value; diff --git a/unit/Makefile b/unit/Makefile index fd1e8d30ec1..7e7218c0fe4 100644 --- a/unit/Makefile +++ b/unit/Makefile @@ -51,6 +51,7 @@ SRC += analyses/ai/ai.cpp \ util/graph.cpp \ util/irep.cpp \ util/irep_sharing.cpp \ + util/json_array.cpp \ util/json_object.cpp \ util/memory_info.cpp \ util/message.cpp \ diff --git a/unit/util/json_array.cpp b/unit/util/json_array.cpp new file mode 100644 index 00000000000..1c233ee25d2 --- /dev/null +++ b/unit/util/json_array.cpp @@ -0,0 +1,66 @@ +/*******************************************************************\ + +Module: Catch tests for json_arrayt + +Author: Diffblue Ltd. + +\*******************************************************************/ + +#include +#include +#include +#include + +#include +#include + +SCENARIO( + "Test that json_arrayt can be constructed from an initializer list.", + "[core][util][json]") +{ + GIVEN("A json_arrayt constructed from an initializer list.") + { + const json_arrayt array{ + json_stringt{"one"}, json_numbert{"2"}, json_stringt{"three"}}; + THEN("The elements of the `json_arrayt` match the initialiser list.") + { + auto it = array.begin(); + REQUIRE(it->kind == jsont::kindt::J_STRING); + REQUIRE(it->value == "one"); + ++it; + REQUIRE(it->kind == jsont::kindt::J_NUMBER); + REQUIRE(it->value == "2"); + ++it; + REQUIRE(it->kind == jsont::kindt::J_STRING); + REQUIRE(it->value == "three"); + ++it; + REQUIRE(it == array.end()); + } + } +} + +SCENARIO( + "Test that json_arrayt can be constructed using `ranget`", + "[core][util][json]") +{ + GIVEN("A vector of strings.") + { + const std::vector input{"foo", "bar"}; + THEN( + "A json_arrayt can be constructed from the vector of strings using range " + "and map.") + { + const json_arrayt array = make_range(input) + .map(constructor_of()) + .collect(); + auto it = array.begin(); + REQUIRE(it->kind == jsont::kindt::J_STRING); + REQUIRE(it->value == "foo"); + ++it; + REQUIRE(it->kind == jsont::kindt::J_STRING); + REQUIRE(it->value == "bar"); + ++it; + REQUIRE(it == array.end()); + } + } +} diff --git a/unit/util/json_object.cpp b/unit/util/json_object.cpp index 9ea4c393207..23096e1a0ab 100644 --- a/unit/util/json_object.cpp +++ b/unit/util/json_object.cpp @@ -11,9 +11,12 @@ Author: Diffblue Ltd. #include #include #include +#include #include #include +#include +#include SCENARIO( "Test that json_objectt is compatible with STL algorithms", @@ -47,3 +50,58 @@ SCENARIO( } } } + +SCENARIO( + "Test that json_objectt can be constructed from an initializer list.", + "[core][util][json]") +{ + GIVEN("A json_objectt constructed from an initializer list.") + { + const json_objectt object{ + {"number", json_numbert{"6"}}, + {"string", json_stringt{"eggs"}}, + {"mice", + json_objectt{{"number", json_numbert{"3"}}, + {"string", json_stringt{"blind"}}}}}; + THEN("The fields of the json_objectt match the initialiser list.") + { + REQUIRE(object["number"].kind == jsont::kindt::J_NUMBER); + REQUIRE(object["number"].value == "6"); + REQUIRE(object["string"].kind == jsont::kindt::J_STRING); + REQUIRE(object["string"].value == "eggs"); + const json_objectt mice = to_json_object(object["mice"]); + REQUIRE(mice["number"].kind == jsont::kindt::J_NUMBER); + REQUIRE(mice["number"].value == "3"); + REQUIRE(mice["string"].kind == jsont::kindt::J_STRING); + REQUIRE(mice["string"].value == "blind"); + } + } +} + +SCENARIO( + "Test that json_objectt can be constructed using `ranget`", + "[core][util][json]") +{ + GIVEN("A vector of numbers.") + { + const std::vector input{1, 2, 3}; + THEN( + "A json_objectt can be constructed from the vector of numbers using " + "range and map.") + { + const json_objectt output = + make_range(input) + .map([](const int number) { + const std::string number_as_string = std::to_string(number); + return make_pair(number_as_string, json_stringt{number_as_string}); + }) + .collect(); + REQUIRE(output["1"].kind == jsont::kindt::J_STRING); + REQUIRE(output["1"].value == "1"); + REQUIRE(output["2"].kind == jsont::kindt::J_STRING); + REQUIRE(output["2"].value == "2"); + REQUIRE(output["3"].kind == jsont::kindt::J_STRING); + REQUIRE(output["3"].value == "3"); + }; + } +}