mirror of
https://github.com/Tencent/rapidjson.git
synced 2025-03-06 04:55:50 +01:00
Initial version (0.1)
git-svn-id: https://rapidjson.googlecode.com/svn/trunk@2 c5894555-1306-4e8d-425f-1f6f381ee07c
This commit is contained in:
parent
0e2c686753
commit
8f8e905306
22
bin/data/glossary.json
Normal file
22
bin/data/glossary.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"glossary": {
|
||||
"title": "example glossary",
|
||||
"GlossDiv": {
|
||||
"title": "S",
|
||||
"GlossList": {
|
||||
"GlossEntry": {
|
||||
"ID": "SGML",
|
||||
"SortAs": "SGML",
|
||||
"GlossTerm": "Standard Generalized Markup Language",
|
||||
"Acronym": "SGML",
|
||||
"Abbrev": "ISO 8879:1986",
|
||||
"GlossDef": {
|
||||
"para": "A meta-markup language, used to create markup languages such as DocBook.",
|
||||
"GlossSeeAlso": ["GML", "XML"]
|
||||
},
|
||||
"GlossSee": "markup"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
27
bin/data/menu.json
Normal file
27
bin/data/menu.json
Normal file
@ -0,0 +1,27 @@
|
||||
{"menu": {
|
||||
"header": "SVG Viewer",
|
||||
"items": [
|
||||
{"id": "Open"},
|
||||
{"id": "OpenNew", "label": "Open New"},
|
||||
null,
|
||||
{"id": "ZoomIn", "label": "Zoom In"},
|
||||
{"id": "ZoomOut", "label": "Zoom Out"},
|
||||
{"id": "OriginalView", "label": "Original View"},
|
||||
null,
|
||||
{"id": "Quality"},
|
||||
{"id": "Pause"},
|
||||
{"id": "Mute"},
|
||||
null,
|
||||
{"id": "Find", "label": "Find..."},
|
||||
{"id": "FindAgain", "label": "Find Again"},
|
||||
{"id": "Copy"},
|
||||
{"id": "CopyAgain", "label": "Copy Again"},
|
||||
{"id": "CopySVG", "label": "Copy SVG"},
|
||||
{"id": "ViewSVG", "label": "View SVG"},
|
||||
{"id": "ViewSource", "label": "View Source"},
|
||||
{"id": "SaveAs", "label": "Save As"},
|
||||
null,
|
||||
{"id": "Help"},
|
||||
{"id": "About", "label": "About Adobe CVG Viewer..."}
|
||||
]
|
||||
}}
|
1
bin/data/readme.txt
Normal file
1
bin/data/readme.txt
Normal file
@ -0,0 +1 @@
|
||||
sample.json is obtained from http://code.google.com/p/json-test-suite/downloads/detail?name=sample.zip
|
3315
bin/data/sample.json
Normal file
3315
bin/data/sample.json
Normal file
File diff suppressed because it is too large
Load Diff
88
bin/data/webapp.json
Normal file
88
bin/data/webapp.json
Normal file
@ -0,0 +1,88 @@
|
||||
{"web-app": {
|
||||
"servlet": [
|
||||
{
|
||||
"servlet-name": "cofaxCDS",
|
||||
"servlet-class": "org.cofax.cds.CDSServlet",
|
||||
"init-param": {
|
||||
"configGlossary:installationAt": "Philadelphia, PA",
|
||||
"configGlossary:adminEmail": "ksm@pobox.com",
|
||||
"configGlossary:poweredBy": "Cofax",
|
||||
"configGlossary:poweredByIcon": "/images/cofax.gif",
|
||||
"configGlossary:staticPath": "/content/static",
|
||||
"templateProcessorClass": "org.cofax.WysiwygTemplate",
|
||||
"templateLoaderClass": "org.cofax.FilesTemplateLoader",
|
||||
"templatePath": "templates",
|
||||
"templateOverridePath": "",
|
||||
"defaultListTemplate": "listTemplate.htm",
|
||||
"defaultFileTemplate": "articleTemplate.htm",
|
||||
"useJSP": false,
|
||||
"jspListTemplate": "listTemplate.jsp",
|
||||
"jspFileTemplate": "articleTemplate.jsp",
|
||||
"cachePackageTagsTrack": 200,
|
||||
"cachePackageTagsStore": 200,
|
||||
"cachePackageTagsRefresh": 60,
|
||||
"cacheTemplatesTrack": 100,
|
||||
"cacheTemplatesStore": 50,
|
||||
"cacheTemplatesRefresh": 15,
|
||||
"cachePagesTrack": 200,
|
||||
"cachePagesStore": 100,
|
||||
"cachePagesRefresh": 10,
|
||||
"cachePagesDirtyRead": 10,
|
||||
"searchEngineListTemplate": "forSearchEnginesList.htm",
|
||||
"searchEngineFileTemplate": "forSearchEngines.htm",
|
||||
"searchEngineRobotsDb": "WEB-INF/robots.db",
|
||||
"useDataStore": true,
|
||||
"dataStoreClass": "org.cofax.SqlDataStore",
|
||||
"redirectionClass": "org.cofax.SqlRedirection",
|
||||
"dataStoreName": "cofax",
|
||||
"dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver",
|
||||
"dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",
|
||||
"dataStoreUser": "sa",
|
||||
"dataStorePassword": "dataStoreTestQuery",
|
||||
"dataStoreTestQuery": "SET NOCOUNT ON;select test='test';",
|
||||
"dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log",
|
||||
"dataStoreInitConns": 10,
|
||||
"dataStoreMaxConns": 100,
|
||||
"dataStoreConnUsageLimit": 100,
|
||||
"dataStoreLogLevel": "debug",
|
||||
"maxUrlLength": 500}},
|
||||
{
|
||||
"servlet-name": "cofaxEmail",
|
||||
"servlet-class": "org.cofax.cds.EmailServlet",
|
||||
"init-param": {
|
||||
"mailHost": "mail1",
|
||||
"mailHostOverride": "mail2"}},
|
||||
{
|
||||
"servlet-name": "cofaxAdmin",
|
||||
"servlet-class": "org.cofax.cds.AdminServlet"},
|
||||
|
||||
{
|
||||
"servlet-name": "fileServlet",
|
||||
"servlet-class": "org.cofax.cds.FileServlet"},
|
||||
{
|
||||
"servlet-name": "cofaxTools",
|
||||
"servlet-class": "org.cofax.cms.CofaxToolsServlet",
|
||||
"init-param": {
|
||||
"templatePath": "toolstemplates/",
|
||||
"log": 1,
|
||||
"logLocation": "/usr/local/tomcat/logs/CofaxTools.log",
|
||||
"logMaxSize": "",
|
||||
"dataLog": 1,
|
||||
"dataLogLocation": "/usr/local/tomcat/logs/dataLog.log",
|
||||
"dataLogMaxSize": "",
|
||||
"removePageCache": "/content/admin/remove?cache=pages&id=",
|
||||
"removeTemplateCache": "/content/admin/remove?cache=templates&id=",
|
||||
"fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder",
|
||||
"lookInContext": 1,
|
||||
"adminGroupID": 4,
|
||||
"betaServer": true}}],
|
||||
"servlet-mapping": {
|
||||
"cofaxCDS": "/",
|
||||
"cofaxEmail": "/cofaxutil/aemail/*",
|
||||
"cofaxAdmin": "/admin/*",
|
||||
"fileServlet": "/static/*",
|
||||
"cofaxTools": "/tools/*"},
|
||||
|
||||
"taglib": {
|
||||
"taglib-uri": "cofax.tld",
|
||||
"taglib-location": "/WEB-INF/tlds/cofax.tld"}}}
|
26
bin/data/widget.json
Normal file
26
bin/data/widget.json
Normal file
@ -0,0 +1,26 @@
|
||||
{"widget": {
|
||||
"debug": "on",
|
||||
"window": {
|
||||
"title": "Sample Konfabulator Widget",
|
||||
"name": "main_window",
|
||||
"width": 500,
|
||||
"height": 500
|
||||
},
|
||||
"image": {
|
||||
"src": "Images/Sun.png",
|
||||
"name": "sun1",
|
||||
"hOffset": 250,
|
||||
"vOffset": 250,
|
||||
"alignment": "center"
|
||||
},
|
||||
"text": {
|
||||
"data": "Click Here",
|
||||
"size": 36,
|
||||
"style": "bold",
|
||||
"name": "text1",
|
||||
"hOffset": 250,
|
||||
"vOffset": 100,
|
||||
"alignment": "center",
|
||||
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
|
||||
}
|
||||
}}
|
1
bin/jsonchecker/fail1.json
Normal file
1
bin/jsonchecker/fail1.json
Normal file
@ -0,0 +1 @@
|
||||
"A JSON payload should be an object or array, not a string."
|
1
bin/jsonchecker/fail10.json
Normal file
1
bin/jsonchecker/fail10.json
Normal file
@ -0,0 +1 @@
|
||||
{"Extra value after close": true} "misplaced quoted value"
|
1
bin/jsonchecker/fail11.json
Normal file
1
bin/jsonchecker/fail11.json
Normal file
@ -0,0 +1 @@
|
||||
{"Illegal expression": 1 + 2}
|
1
bin/jsonchecker/fail12.json
Normal file
1
bin/jsonchecker/fail12.json
Normal file
@ -0,0 +1 @@
|
||||
{"Illegal invocation": alert()}
|
1
bin/jsonchecker/fail13.json
Normal file
1
bin/jsonchecker/fail13.json
Normal file
@ -0,0 +1 @@
|
||||
{"Numbers cannot have leading zeroes": 013}
|
1
bin/jsonchecker/fail14.json
Normal file
1
bin/jsonchecker/fail14.json
Normal file
@ -0,0 +1 @@
|
||||
{"Numbers cannot be hex": 0x14}
|
1
bin/jsonchecker/fail15.json
Normal file
1
bin/jsonchecker/fail15.json
Normal file
@ -0,0 +1 @@
|
||||
["Illegal backslash escape: \x15"]
|
1
bin/jsonchecker/fail16.json
Normal file
1
bin/jsonchecker/fail16.json
Normal file
@ -0,0 +1 @@
|
||||
[\naked]
|
1
bin/jsonchecker/fail17.json
Normal file
1
bin/jsonchecker/fail17.json
Normal file
@ -0,0 +1 @@
|
||||
["Illegal backslash escape: \017"]
|
1
bin/jsonchecker/fail18.json
Normal file
1
bin/jsonchecker/fail18.json
Normal file
@ -0,0 +1 @@
|
||||
[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]
|
1
bin/jsonchecker/fail19.json
Normal file
1
bin/jsonchecker/fail19.json
Normal file
@ -0,0 +1 @@
|
||||
{"Missing colon" null}
|
1
bin/jsonchecker/fail2.json
Normal file
1
bin/jsonchecker/fail2.json
Normal file
@ -0,0 +1 @@
|
||||
["Unclosed array"
|
1
bin/jsonchecker/fail20.json
Normal file
1
bin/jsonchecker/fail20.json
Normal file
@ -0,0 +1 @@
|
||||
{"Double colon":: null}
|
1
bin/jsonchecker/fail21.json
Normal file
1
bin/jsonchecker/fail21.json
Normal file
@ -0,0 +1 @@
|
||||
{"Comma instead of colon", null}
|
1
bin/jsonchecker/fail22.json
Normal file
1
bin/jsonchecker/fail22.json
Normal file
@ -0,0 +1 @@
|
||||
["Colon instead of comma": false]
|
1
bin/jsonchecker/fail23.json
Normal file
1
bin/jsonchecker/fail23.json
Normal file
@ -0,0 +1 @@
|
||||
["Bad value", truth]
|
1
bin/jsonchecker/fail24.json
Normal file
1
bin/jsonchecker/fail24.json
Normal file
@ -0,0 +1 @@
|
||||
['single quote']
|
1
bin/jsonchecker/fail25.json
Normal file
1
bin/jsonchecker/fail25.json
Normal file
@ -0,0 +1 @@
|
||||
[" tab character in string "]
|
1
bin/jsonchecker/fail26.json
Normal file
1
bin/jsonchecker/fail26.json
Normal file
@ -0,0 +1 @@
|
||||
["tab\ character\ in\ string\ "]
|
2
bin/jsonchecker/fail27.json
Normal file
2
bin/jsonchecker/fail27.json
Normal file
@ -0,0 +1,2 @@
|
||||
["line
|
||||
break"]
|
2
bin/jsonchecker/fail28.json
Normal file
2
bin/jsonchecker/fail28.json
Normal file
@ -0,0 +1,2 @@
|
||||
["line\
|
||||
break"]
|
1
bin/jsonchecker/fail29.json
Normal file
1
bin/jsonchecker/fail29.json
Normal file
@ -0,0 +1 @@
|
||||
[0e]
|
1
bin/jsonchecker/fail3.json
Normal file
1
bin/jsonchecker/fail3.json
Normal file
@ -0,0 +1 @@
|
||||
{unquoted_key: "keys must be quoted"}
|
1
bin/jsonchecker/fail30.json
Normal file
1
bin/jsonchecker/fail30.json
Normal file
@ -0,0 +1 @@
|
||||
[0e+]
|
1
bin/jsonchecker/fail31.json
Normal file
1
bin/jsonchecker/fail31.json
Normal file
@ -0,0 +1 @@
|
||||
[0e+-1]
|
1
bin/jsonchecker/fail32.json
Normal file
1
bin/jsonchecker/fail32.json
Normal file
@ -0,0 +1 @@
|
||||
{"Comma instead if closing brace": true,
|
1
bin/jsonchecker/fail33.json
Normal file
1
bin/jsonchecker/fail33.json
Normal file
@ -0,0 +1 @@
|
||||
["mismatch"}
|
1
bin/jsonchecker/fail4.json
Normal file
1
bin/jsonchecker/fail4.json
Normal file
@ -0,0 +1 @@
|
||||
["extra comma",]
|
1
bin/jsonchecker/fail5.json
Normal file
1
bin/jsonchecker/fail5.json
Normal file
@ -0,0 +1 @@
|
||||
["double extra comma",,]
|
1
bin/jsonchecker/fail6.json
Normal file
1
bin/jsonchecker/fail6.json
Normal file
@ -0,0 +1 @@
|
||||
[ , "<-- missing value"]
|
1
bin/jsonchecker/fail7.json
Normal file
1
bin/jsonchecker/fail7.json
Normal file
@ -0,0 +1 @@
|
||||
["Comma after the close"],
|
1
bin/jsonchecker/fail8.json
Normal file
1
bin/jsonchecker/fail8.json
Normal file
@ -0,0 +1 @@
|
||||
["Extra close"]]
|
1
bin/jsonchecker/fail9.json
Normal file
1
bin/jsonchecker/fail9.json
Normal file
@ -0,0 +1 @@
|
||||
{"Extra comma": true,}
|
58
bin/jsonchecker/pass1.json
Normal file
58
bin/jsonchecker/pass1.json
Normal file
@ -0,0 +1,58 @@
|
||||
[
|
||||
"JSON Test Pattern pass1",
|
||||
{"object with 1 member":["array with 1 element"]},
|
||||
{},
|
||||
[],
|
||||
-42,
|
||||
true,
|
||||
false,
|
||||
null,
|
||||
{
|
||||
"integer": 1234567890,
|
||||
"real": -9876.543210,
|
||||
"e": 0.123456789e-12,
|
||||
"E": 1.234567890E+34,
|
||||
"": 23456789012E66,
|
||||
"zero": 0,
|
||||
"one": 1,
|
||||
"space": " ",
|
||||
"quote": "\"",
|
||||
"backslash": "\\",
|
||||
"controls": "\b\f\n\r\t",
|
||||
"slash": "/ & \/",
|
||||
"alpha": "abcdefghijklmnopqrstuvwyz",
|
||||
"ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
|
||||
"digit": "0123456789",
|
||||
"0123456789": "digit",
|
||||
"special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
|
||||
"hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
|
||||
"true": true,
|
||||
"false": false,
|
||||
"null": null,
|
||||
"array":[ ],
|
||||
"object":{ },
|
||||
"address": "50 St. James Street",
|
||||
"url": "http://www.JSON.org/",
|
||||
"comment": "// /* <!-- --",
|
||||
"# -- --> */": " ",
|
||||
" s p a c e d " :[1,2 , 3
|
||||
|
||||
,
|
||||
|
||||
4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7],
|
||||
"jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
|
||||
"quotes": "" \u0022 %22 0x22 034 "",
|
||||
"\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
|
||||
: "A key can be any string"
|
||||
},
|
||||
0.5 ,98.6
|
||||
,
|
||||
99.44
|
||||
,
|
||||
|
||||
1066,
|
||||
1e1,
|
||||
0.1e1,
|
||||
1e-1,
|
||||
1e00,2e+00,2e-00
|
||||
,"rosebud"]
|
1
bin/jsonchecker/pass2.json
Normal file
1
bin/jsonchecker/pass2.json
Normal file
@ -0,0 +1 @@
|
||||
[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
|
6
bin/jsonchecker/pass3.json
Normal file
6
bin/jsonchecker/pass3.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"JSON Test Pattern pass3": {
|
||||
"The outermost value": "must be an object or array.",
|
||||
"In this test": "It is an object."
|
||||
}
|
||||
}
|
3
bin/jsonchecker/readme.txt
Normal file
3
bin/jsonchecker/readme.txt
Normal file
@ -0,0 +1,3 @@
|
||||
Test suite from http://json.org/JSON_checker/.
|
||||
|
||||
If the JSON_checker is working correctly, it must accept all of the pass*.json files and reject all of the fail*.json files.
|
1789
build/Doxyfile
Normal file
1789
build/Doxyfile
Normal file
File diff suppressed because it is too large
Load Diff
4
build/premake
Normal file
4
build/premake
Normal file
@ -0,0 +1,4 @@
|
||||
premake4 vs2005
|
||||
premake4 vs2008
|
||||
premake4 vs2010
|
||||
premake4 gmake
|
5
build/premake.bat
Normal file
5
build/premake.bat
Normal file
@ -0,0 +1,5 @@
|
||||
@echo off
|
||||
premake4 vs2005
|
||||
premake4 vs2008
|
||||
premake4 vs2010
|
||||
premake4 gmake
|
165
build/premake4.lua
Normal file
165
build/premake4.lua
Normal file
@ -0,0 +1,165 @@
|
||||
function setTargetObjDir(outDir)
|
||||
for _, cfg in ipairs(configurations()) do
|
||||
for _, plat in ipairs(platforms()) do
|
||||
local action = _ACTION or ""
|
||||
|
||||
local prj = project()
|
||||
|
||||
--"_debug_win32_vs2008"
|
||||
local suffix = "_" .. cfg .. "_" .. plat .. "_" .. action
|
||||
|
||||
targetPath = outDir
|
||||
|
||||
suffix = string.lower(suffix)
|
||||
|
||||
local obj_path = "../intermediate/" .. cfg .. "/" .. action .. "/" .. prj.name
|
||||
|
||||
obj_path = string.lower(obj_path)
|
||||
|
||||
configuration {cfg, plat}
|
||||
targetdir(targetPath)
|
||||
objdir(obj_path)
|
||||
targetsuffix(suffix)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function linkLib(libBaseName)
|
||||
for _, cfg in ipairs(configurations()) do
|
||||
for _, plat in ipairs(platforms()) do
|
||||
local action = _ACTION or ""
|
||||
|
||||
local prj = project()
|
||||
|
||||
local cfgName = cfg
|
||||
|
||||
--"_debug_win32_vs2008"
|
||||
local suffix = "_" .. cfgName .. "_" .. plat .. "_" .. action
|
||||
|
||||
libFullName = libBaseName .. string.lower(suffix)
|
||||
|
||||
configuration {cfg, plat}
|
||||
links(libFullName)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
solution "test"
|
||||
configurations { "debug", "release" }
|
||||
platforms { "x32", "x64" }
|
||||
|
||||
location ("./" .. (_ACTION or ""))
|
||||
language "C++"
|
||||
|
||||
configuration "debug"
|
||||
defines { "DEBUG" }
|
||||
flags { "Symbols" }
|
||||
|
||||
configuration "release"
|
||||
defines { "NDEBUG" }
|
||||
flags { "Optimize" }
|
||||
|
||||
configuration "vs*"
|
||||
defines { "_CRT_SECURE_NO_WARNINGS" }
|
||||
|
||||
configuration "gmake"
|
||||
buildoptions "-msse4.2"
|
||||
|
||||
project "gtest"
|
||||
kind "StaticLib"
|
||||
files {
|
||||
"../thirdparty/gtest/src/gtest-all.cc",
|
||||
"../thirdparty/gtest/src/**.h",
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"../thirdparty/gtest/",
|
||||
"../thirdparty/gtest/include",
|
||||
}
|
||||
|
||||
setTargetObjDir("../thirdparty/lib")
|
||||
|
||||
project "unittest"
|
||||
kind "ConsoleApp"
|
||||
|
||||
files {
|
||||
"../include/**.h",
|
||||
"../test/unittest/**.cpp",
|
||||
"../test/unittest/**.h",
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"../include/",
|
||||
"../thirdparty/gtest/include/",
|
||||
}
|
||||
|
||||
libdirs "../thirdparty/lib"
|
||||
|
||||
setTargetObjDir("../bin")
|
||||
|
||||
linkLib "gtest"
|
||||
links "gtest"
|
||||
|
||||
project "perftest"
|
||||
kind "ConsoleApp"
|
||||
|
||||
files {
|
||||
"../include/**.h",
|
||||
"../test/perftest/**.cpp",
|
||||
"../test/perftest/**.c",
|
||||
"../test/perftest/**.h",
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"../include/",
|
||||
"../thirdparty/gtest/include/",
|
||||
"../thirdparty/",
|
||||
"../thirdparty/jsoncpp/include/",
|
||||
"../thirdparty/libjson/",
|
||||
"../thirdparty/yajl/include/",
|
||||
}
|
||||
|
||||
libdirs "../thirdparty/lib"
|
||||
|
||||
setTargetObjDir("../bin")
|
||||
|
||||
linkLib "gtest"
|
||||
links "gtest"
|
||||
|
||||
solution "example"
|
||||
configurations { "debug", "release" }
|
||||
platforms { "x32", "x64" }
|
||||
location ("./" .. (_ACTION or ""))
|
||||
language "C++"
|
||||
includedirs "../include/"
|
||||
|
||||
configuration "debug"
|
||||
defines { "DEBUG" }
|
||||
flags { "Symbols" }
|
||||
|
||||
configuration "release"
|
||||
defines { "NDEBUG" }
|
||||
flags { "Optimize", "EnableSSE2" }
|
||||
|
||||
configuration "vs*"
|
||||
defines { "_CRT_SECURE_NO_WARNINGS" }
|
||||
|
||||
project "condense"
|
||||
kind "ConsoleApp"
|
||||
files "../example/condense/*"
|
||||
setTargetObjDir("../bin")
|
||||
|
||||
project "pretty"
|
||||
kind "ConsoleApp"
|
||||
files "../example/pretty/*"
|
||||
setTargetObjDir("../bin")
|
||||
|
||||
project "tutorial"
|
||||
kind "ConsoleApp"
|
||||
files "../example/tutorial/*"
|
||||
setTargetObjDir("../bin")
|
||||
|
||||
project "serialize"
|
||||
kind "ConsoleApp"
|
||||
files "../example/serialize/*"
|
||||
setTargetObjDir("../bin")
|
28
example/condense/condense.cpp
Normal file
28
example/condense/condense.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
// JSON condenser exmaple
|
||||
|
||||
// This example parses JSON text from stdin with validation,
|
||||
// and re-output the JSON content to stdout without whitespace.
|
||||
|
||||
#include "rapidjson/reader.h"
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/filestream.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// Prepare JSON reader and input stream.
|
||||
Reader reader;
|
||||
FileStream is(stdin);
|
||||
|
||||
// Prepare JSON writer and output stream.
|
||||
FileStream os(stdout);
|
||||
Writer<FileStream> writer(os);
|
||||
|
||||
// JSON reader parse from the input stream and let writer generate the output.
|
||||
if (!reader.Parse<0>(is, writer)) {
|
||||
fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), reader.GetParseError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
25
example/pretty/pretty.cpp
Normal file
25
example/pretty/pretty.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
// JSON pretty formatting example
|
||||
|
||||
#include "rapidjson/reader.h"
|
||||
#include "rapidjson/prettywriter.h"
|
||||
#include "rapidjson/filestream.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// Prepare reader and input stream.
|
||||
Reader reader;
|
||||
FileStream is(stdin);
|
||||
|
||||
// Prepare writer and output stream.
|
||||
FileStream os(stdout);
|
||||
PrettyWriter<FileStream> writer(os);
|
||||
|
||||
// JSON reader parse from the input stream and let writer generate the output.
|
||||
if (!reader.Parse<0>(is, writer)) {
|
||||
fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), reader.GetParseError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
129
example/serialize/serialize.cpp
Normal file
129
example/serialize/serialize.cpp
Normal file
@ -0,0 +1,129 @@
|
||||
// Serialize example
|
||||
// This example shows writing JSON string with writer directly.
|
||||
|
||||
#include "rapidjson/prettywriter.h" // for stringify JSON
|
||||
#include "rapidjson/filestream.h" // wrapper of C stream for prettywriter as output
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
class Person {
|
||||
public:
|
||||
Person(const std::string& name, unsigned age) : name_(name), age_(age) {}
|
||||
virtual ~Person() {}
|
||||
|
||||
protected:
|
||||
template <typename Writer>
|
||||
void Serialize(Writer& writer) const {
|
||||
// This base class just write out name-value pairs, without wrapping within an object.
|
||||
writer.String("name");
|
||||
writer.String(name_.c_str(), (SizeType)name_.length()); // Suppling length of string is faster.
|
||||
|
||||
writer.String("age");
|
||||
writer.Uint(age_);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
unsigned age_;
|
||||
};
|
||||
|
||||
class Education {
|
||||
public:
|
||||
Education(const std::string& school, double GPA) : school_(school), GPA_(GPA) {}
|
||||
|
||||
template <typename Writer>
|
||||
void Serialize(Writer& writer) const {
|
||||
writer.StartObject();
|
||||
|
||||
writer.String("school");
|
||||
writer.String(school_.c_str(), (SizeType)school_.length());
|
||||
|
||||
writer.String("GPA");
|
||||
writer.Double(GPA_);
|
||||
|
||||
writer.EndObject();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string school_;
|
||||
double GPA_;
|
||||
};
|
||||
|
||||
class Dependent : public Person {
|
||||
public:
|
||||
Dependent(const std::string& name, unsigned age, Education* education = 0) : Person(name, age), education_(education) {}
|
||||
Dependent(const Dependent& rhs) : Person(rhs) { education_ = (rhs.education_ == 0) ? 0 : new Education(*rhs.education_); }
|
||||
~Dependent() { delete education_; }
|
||||
|
||||
template <typename Writer>
|
||||
void Serialize(Writer& writer) const {
|
||||
writer.StartObject();
|
||||
|
||||
Person::Serialize(writer);
|
||||
|
||||
writer.String("education");
|
||||
if (education_)
|
||||
education_->Serialize(writer);
|
||||
else
|
||||
writer.Null();
|
||||
|
||||
writer.EndObject();
|
||||
}
|
||||
|
||||
private:
|
||||
Education *education_;
|
||||
};
|
||||
|
||||
class Employee : public Person {
|
||||
public:
|
||||
Employee(const std::string& name, unsigned age, bool married) : Person(name, age), married_(married) {}
|
||||
|
||||
void AddDependent(const Dependent& dependent) {
|
||||
dependents_.push_back(dependent);
|
||||
}
|
||||
|
||||
template <typename Writer>
|
||||
void Serialize(Writer& writer) const {
|
||||
writer.StartObject();
|
||||
|
||||
Person::Serialize(writer);
|
||||
|
||||
writer.String("married");
|
||||
writer.Bool(married_);
|
||||
|
||||
writer.String(("dependents"));
|
||||
writer.StartArray();
|
||||
for (std::vector<Dependent>::const_iterator dependentItr = dependents_.begin(); dependentItr != dependents_.end(); ++dependentItr)
|
||||
dependentItr->Serialize(writer);
|
||||
writer.EndArray();
|
||||
|
||||
writer.EndObject();
|
||||
}
|
||||
|
||||
private:
|
||||
bool married_;
|
||||
std::vector<Dependent> dependents_;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
std::vector<Employee> employees;
|
||||
|
||||
employees.push_back(Employee("Milo YIP", 34, true));
|
||||
employees.back().AddDependent(Dependent("Lua YIP", 3, new Education("Happy Kindergarten", 3.5)));
|
||||
employees.back().AddDependent(Dependent("Mio YIP", 1));
|
||||
|
||||
employees.push_back(Employee("Percy TSE", 30, false));
|
||||
|
||||
FileStream s(stdout);
|
||||
PrettyWriter<FileStream> writer(s); // Can also use Writer for condensed formatting
|
||||
|
||||
writer.StartArray();
|
||||
for (std::vector<Employee>::const_iterator employeeItr = employees.begin(); employeeItr != employees.end(); ++employeeItr)
|
||||
employeeItr->Serialize(writer);
|
||||
writer.EndArray();
|
||||
|
||||
return 0;
|
||||
}
|
133
example/tutorial/tutorial.cpp
Normal file
133
example/tutorial/tutorial.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
// Hello World example
|
||||
// This example shows basic usage of DOM-style API.
|
||||
|
||||
#include "rapidjson/document.h" // rapidjson's DOM-style API
|
||||
#include "rapidjson/prettywriter.h" // for stringify JSON
|
||||
#include "rapidjson/filestream.h" // wrapper of C stream for prettywriter as output
|
||||
#include <cstdio>
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// 1. Parse a JSON text string to a document.
|
||||
|
||||
const char json[] = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ";
|
||||
printf("Original JSON:\n %s\n", json);
|
||||
|
||||
Document document; // Default template parameter uses UTF8 and MemoryPoolAllocator.
|
||||
|
||||
#if 0
|
||||
// "normal" parsing, decode strings to new buffers. Can use other input stream via ParseStream().
|
||||
if (document.Parse<0>(json).HasParseError())
|
||||
return 1;
|
||||
#else
|
||||
// In-situ parsing, decode strings directly in the source string. Source must be string.
|
||||
char buffer[sizeof(json)];
|
||||
memcpy(buffer, json, sizeof(json));
|
||||
if (document.ParseInsitu<0>(buffer).HasParseError())
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
printf("\nParsing to document succeeded.\n");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// 2. Access values in document.
|
||||
|
||||
printf("\nAccess values in document:\n");
|
||||
assert(document.IsObject()); // Document is a JSON value represents the root of DOM. Root can be either an object or array.
|
||||
|
||||
assert(document.HasMember("hello"));
|
||||
assert(document["hello"].IsString());
|
||||
printf("hello = %s\n", document["hello"].GetString());
|
||||
|
||||
assert(document["t"].IsBool()); // JSON true/false are bool. Can also uses more specific function IsTrue().
|
||||
printf("t = %s\n", document["t"].GetBool() ? "true" : "false");
|
||||
|
||||
assert(document["f"].IsBool());
|
||||
printf("f = %s\n", document["f"].GetBool() ? "true" : "false");
|
||||
|
||||
printf("n = %s\n", document["n"].IsNull() ? "null" : "?");
|
||||
|
||||
assert(document["i"].IsNumber()); // Number is a JSON type, but C++ needs more specific type.
|
||||
assert(document["i"].IsInt()); // In this case, IsUint()/IsInt64()/IsUInt64() also return true.
|
||||
printf("i = %d\n", document["i"].GetInt()); // Alternative (int)document["i"]
|
||||
|
||||
assert(document["pi"].IsNumber());
|
||||
assert(document["pi"].IsDouble());
|
||||
printf("pi = %g\n", document["pi"].GetDouble());
|
||||
|
||||
{
|
||||
const Value& a = document["a"]; // Using a reference for consecutive access is handy and faster.
|
||||
assert(a.IsArray());
|
||||
for (SizeType i = 0; i < a.Size(); i++) // rapidjson uses SizeType instead of size_t.
|
||||
printf("a[%d] = %d\n", i, a[i].GetInt());
|
||||
|
||||
// Note:
|
||||
//int x = a[0].GetInt(); // Error: operator[ is ambiguous, as 0 also mean a null pointer of const char* type.
|
||||
int y = a[SizeType(0)].GetInt(); // Cast to SizeType will work.
|
||||
int z = a[0u].GetInt(); // This works too.
|
||||
}
|
||||
|
||||
// 3. Modify values in document.
|
||||
|
||||
// Change i to a bigger number
|
||||
{
|
||||
uint64_t f20 = 1; // compute factorial of 20
|
||||
for (uint64_t j = 1; j <= 20; j++)
|
||||
f20 *= j;
|
||||
document["i"] = f20; // Alternate form: document["i"].SetUint64(f20)
|
||||
assert(!document["i"].IsInt()); // No longer can be cast as int or uint.
|
||||
}
|
||||
|
||||
// Adding values to array.
|
||||
{
|
||||
Value& a = document["a"]; // This time we uses non-const reference.
|
||||
Document::AllocatorType& allocator = document.GetAllocator();
|
||||
for (int i = 5; i <= 10; i++)
|
||||
a.PushBack(i, allocator); // May look a bit strange, allocator is needed for potentially realloc. We normally uses the document's.
|
||||
|
||||
// Fluent API
|
||||
a.PushBack("Lua", allocator).PushBack("Mio", allocator);
|
||||
}
|
||||
|
||||
// Making string values.
|
||||
|
||||
// This version of SetString() just store the pointer to the string.
|
||||
// So it is for literal and string that exists within value's life-cycle.
|
||||
{
|
||||
document["hello"] = "rapidjson"; // This will invoke strlen()
|
||||
// Faster version:
|
||||
// document["hello"].SetString("rapidjson", 9);
|
||||
}
|
||||
|
||||
// This version of SetString() needs an allocator, which means it will allocate a new buffer and copy the the string into the buffer.
|
||||
Value author;
|
||||
{
|
||||
char buffer[10];
|
||||
int len = sprintf(buffer, "%s %s", "Milo", "Yip"); // synthetic example of dynamically created string.
|
||||
|
||||
author.SetString(buffer, len, document.GetAllocator());
|
||||
// Shorter but slower version:
|
||||
// document["hello"].SetString(buffer, document.GetAllocator());
|
||||
|
||||
// Constructor version:
|
||||
// Value author(buffer, len, document.GetAllocator());
|
||||
// Value author(buffer, document.GetAllocator());
|
||||
memset(buffer, 0, sizeof(buffer)); // For demonstration purpose.
|
||||
}
|
||||
// Variable 'buffer' is unusable now but 'author' has already made a copy.
|
||||
document.AddMember("author", author, document.GetAllocator());
|
||||
|
||||
assert(author.IsNull()); // Move semantic for assignment. After this variable is assigned as a member, the variable becomes null.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// 4. Stringify JSON
|
||||
|
||||
printf("\nModified JSON with reformatting:\n");
|
||||
FileStream f(stdout);
|
||||
PrettyWriter<FileStream> writer(f);
|
||||
document.Accept(writer); // Accept() traverses the DOM and generates Handler events.
|
||||
|
||||
return 0;
|
||||
}
|
806
include/rapidjson/document.h
Normal file
806
include/rapidjson/document.h
Normal file
@ -0,0 +1,806 @@
|
||||
#ifndef RAPIDJSON_DOCUMENT_H_
|
||||
#define RAPIDJSON_DOCUMENT_H_
|
||||
|
||||
#include "reader.h"
|
||||
#include "internal/strfunc.h"
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GenericValue
|
||||
|
||||
//! Represents a JSON value. Use Value for UTF8 encoding and default allocator.
|
||||
/*!
|
||||
A JSON value can be one of 7 types. This class is a variant type supporting
|
||||
these types.
|
||||
|
||||
Use the Value if UTF8 and default allocator
|
||||
|
||||
\tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document)
|
||||
\tparam Allocator Allocator type for allocating memory of object, array and string.
|
||||
*/
|
||||
#pragma pack (push, 4)
|
||||
template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
|
||||
class GenericValue {
|
||||
public:
|
||||
//! Name-value pair in an object.
|
||||
struct Member {
|
||||
GenericValue<Encoding, Allocator> name; //!< name of member (must be a string)
|
||||
GenericValue<Encoding, Allocator> value; //!< value of member.
|
||||
};
|
||||
|
||||
typedef Encoding EncodingType; //!< Encoding type from template parameter.
|
||||
typedef Allocator AllocatorType; //!< Allocator type from template parameter.
|
||||
typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
|
||||
typedef Member* MemberIterator; //!< Member iterator for iterating in object.
|
||||
typedef const Member* ConstMemberIterator; //!< Constant member iterator for iterating in object.
|
||||
typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array.
|
||||
typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array.
|
||||
|
||||
//!@name Constructors and destructor.
|
||||
//@{
|
||||
|
||||
//! Default constructor creates a null value.
|
||||
GenericValue() : flags_(kNullFlag) {}
|
||||
|
||||
//! Copy constructor is not permitted.
|
||||
private:
|
||||
GenericValue(const GenericValue& rhs);
|
||||
|
||||
public:
|
||||
|
||||
//! Constructor with JSON value type.
|
||||
/*! This creates a Value of specified type with default content.
|
||||
\param type Type of the value.
|
||||
\note Default content for number is zero.
|
||||
*/
|
||||
GenericValue(Type type) {
|
||||
static const unsigned defaultFlags[7] = {
|
||||
kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kConstStringFlag,
|
||||
kNumberFlag | kIntFlag | kUintFlag | kInt64Flag | kUint64Flag | kDoubleFlag
|
||||
};
|
||||
RAPIDJSON_ASSERT(type <= kNumberType);
|
||||
flags_ = defaultFlags[type];
|
||||
memset(&data_, 0, sizeof(data_));
|
||||
}
|
||||
|
||||
//! Constructor for boolean value.
|
||||
GenericValue(bool b) : flags_(b ? kTrueFlag : kFalseFlag) {}
|
||||
|
||||
//! Constructor for int value.
|
||||
GenericValue(int i) : flags_(kNumberIntFlag) {
|
||||
data_.n.i64 = i;
|
||||
if (i >= 0)
|
||||
flags_ |= kUintFlag | kUint64Flag;
|
||||
}
|
||||
|
||||
//! Constructor for unsigned value.
|
||||
GenericValue(unsigned u) : flags_(kNumberUintFlag) {
|
||||
data_.n.u64 = u;
|
||||
if (!(u & 0x80000000))
|
||||
flags_ |= kIntFlag | kInt64Flag;
|
||||
}
|
||||
|
||||
//! Constructor for int64_t value.
|
||||
GenericValue(int64_t i64) : flags_(kNumberInt64Flag) {
|
||||
data_.n.i64 = i64;
|
||||
if (i64 >= 0) {
|
||||
flags_ |= kNumberUint64Flag;
|
||||
if (!(i64 & 0xFFFFFFFF00000000LL))
|
||||
flags_ |= kUintFlag;
|
||||
if (!(i64 & 0xFFFFFFFF80000000LL))
|
||||
flags_ |= kIntFlag;
|
||||
}
|
||||
else if (i64 >= -2147483648LL)
|
||||
flags_ |= kIntFlag;
|
||||
}
|
||||
|
||||
//! Constructor for uint64_t value.
|
||||
GenericValue(uint64_t u64) : flags_(kNumberUint64Flag) {
|
||||
data_.n.u64 = u64;
|
||||
if (!(u64 & 0x8000000000000000L))
|
||||
flags_ |= kInt64Flag;
|
||||
if (!(u64 & 0xFFFFFFFF00000000L))
|
||||
flags_ |= kUintFlag;
|
||||
if (!(u64 & 0xFFFFFFFF80000000L))
|
||||
flags_ |= kIntFlag;
|
||||
}
|
||||
|
||||
//! Constructor for double value.
|
||||
GenericValue(double d) : flags_(kNumberDoubleFlag) { data_.n.d = d; }
|
||||
|
||||
//! Constructor for constant string (i.e. do not make a copy of string)
|
||||
GenericValue(const Ch* s, SizeType length) {
|
||||
RAPIDJSON_ASSERT(s != NULL);
|
||||
flags_ = kConstStringFlag;
|
||||
data_.s.str = s;
|
||||
data_.s.length = length;
|
||||
}
|
||||
|
||||
//! Constructor for constant string (i.e. do not make a copy of string)
|
||||
GenericValue(const Ch* s) { SetStringRaw(s, internal::StrLen(s)); }
|
||||
|
||||
//! Constructor for copy-string (i.e. do make a copy of string)
|
||||
GenericValue(const Ch* s, SizeType length, Allocator& allocator) { SetStringRaw(s, length, allocator); }
|
||||
|
||||
//! Constructor for copy-string (i.e. do make a copy of string)
|
||||
GenericValue(const Ch*s, Allocator& allocator) { SetStringRaw(s, internal::StrLen(s), allocator); }
|
||||
|
||||
//! Destructor.
|
||||
/*! Need to destruct elements of array, members of object, or copy-string.
|
||||
*/
|
||||
~GenericValue() {
|
||||
if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
|
||||
switch(flags_) {
|
||||
case kArrayFlag:
|
||||
for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)
|
||||
v->~GenericValue();
|
||||
Allocator::Free(data_.a.elements);
|
||||
break;
|
||||
|
||||
case kObjectFlag:
|
||||
for (Member* m = data_.o.members; m != data_.o.members + data_.o.size; ++m) {
|
||||
m->name.~GenericValue();
|
||||
m->value.~GenericValue();
|
||||
}
|
||||
Allocator::Free(data_.o.members);
|
||||
break;
|
||||
|
||||
case kCopyStringFlag:
|
||||
Allocator::Free((void*)data_.s.str);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
//!@name Assignment operators
|
||||
//@{
|
||||
|
||||
//! Assignment with move semantics.
|
||||
/*! \param rhs Source of the assignment. It will become a null value after assignment.
|
||||
*/
|
||||
GenericValue& operator=(GenericValue& rhs) {
|
||||
RAPIDJSON_ASSERT(this != &rhs);
|
||||
this->~GenericValue();
|
||||
memcpy(this, &rhs, sizeof(GenericValue));
|
||||
rhs.flags_ = kNullFlag;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Assignment with primitive types.
|
||||
/*! \tparam T Either Type, int, unsigned, int64_t, uint64_t, const Ch*
|
||||
\param value The value to be assigned.
|
||||
*/
|
||||
template <typename T>
|
||||
GenericValue& operator=(T value) {
|
||||
this->~GenericValue();
|
||||
new (this) GenericValue(value);
|
||||
return *this;
|
||||
}
|
||||
//@}
|
||||
|
||||
//!@name Type
|
||||
//@{
|
||||
|
||||
Type GetType() const { return static_cast<Type>(flags_ & kTypeMask); }
|
||||
bool IsNull() const { return flags_ == kNullFlag; }
|
||||
bool IsFalse() const { return flags_ == kFalseFlag; }
|
||||
bool IsTrue() const { return flags_ == kTrueFlag; }
|
||||
bool IsBool() const { return (flags_ & kBoolFlag) != 0; }
|
||||
bool IsObject() const { return flags_ == kObjectFlag; }
|
||||
bool IsArray() const { return flags_ == kArrayFlag; }
|
||||
bool IsNumber() const { return (flags_ & kNumberFlag) != 0; }
|
||||
bool IsInt() const { return (flags_ & kIntFlag) != 0; }
|
||||
bool IsUint() const { return (flags_ & kUintFlag) != 0; }
|
||||
bool IsInt64() const { return (flags_ & kInt64Flag) != 0; }
|
||||
bool IsUint64() const { return (flags_ & kUint64Flag) != 0; }
|
||||
bool IsDouble() const { return (flags_ & kDoubleFlag) != 0; }
|
||||
bool IsString() const { return (flags_ & kStringFlag) != 0; }
|
||||
|
||||
//@}
|
||||
|
||||
//!@name Null
|
||||
//@{
|
||||
|
||||
GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; }
|
||||
|
||||
//@}
|
||||
|
||||
//!@name Bool
|
||||
//@{
|
||||
|
||||
bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return flags_ == kTrueFlag; }
|
||||
GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; }
|
||||
|
||||
//@}
|
||||
|
||||
//!@name Object
|
||||
//@{
|
||||
|
||||
//! Set this value as an empty object.
|
||||
GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; }
|
||||
|
||||
//! Get the value associated with the object's name.
|
||||
GenericValue& operator[](const Ch* name) {
|
||||
if (Member* member = FindMember(name))
|
||||
return member->value;
|
||||
else {
|
||||
static GenericValue NullValue;
|
||||
return NullValue;
|
||||
}
|
||||
}
|
||||
const GenericValue& operator[](const Ch* name) const { return const_cast<GenericValue&>(*this)[name]; }
|
||||
|
||||
//! Member iterators.
|
||||
ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.members; }
|
||||
ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.members + data_.o.size; }
|
||||
MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return data_.o.members; }
|
||||
MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return data_.o.members + data_.o.size; }
|
||||
|
||||
//! Check whether a member exists in the object.
|
||||
bool HasMember(const Ch* name) const { return FindMember(name) != 0; }
|
||||
|
||||
//! Add a member (name-value pair) to the object.
|
||||
/*! \param name A string value as name of member.
|
||||
\param value Value of any type.
|
||||
\param allocator Allocator for reallocating memory.
|
||||
\return The value itself for fluent API.
|
||||
\note The ownership of name and value will be transfered to this object if success.
|
||||
*/
|
||||
GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
|
||||
RAPIDJSON_ASSERT(IsObject());
|
||||
RAPIDJSON_ASSERT(name.IsString());
|
||||
Object& o = data_.o;
|
||||
if (o.size >= o.capacity) {
|
||||
if (o.capacity == 0) {
|
||||
o.capacity = kDefaultObjectCapacity;
|
||||
o.members = (Member*)allocator.Malloc(o.capacity * sizeof(Member));
|
||||
}
|
||||
else {
|
||||
SizeType oldCapacity = o.capacity;
|
||||
o.capacity *= 2;
|
||||
o.members = (Member*)allocator.Realloc(o.members, oldCapacity * sizeof(Member), o.capacity * sizeof(Member));
|
||||
}
|
||||
}
|
||||
o.members[o.size].name = name;
|
||||
o.members[o.size].value = value;
|
||||
o.size++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
GenericValue& AddMember(const char* name, Allocator& nameAllocator, GenericValue& value, Allocator& allocator) {
|
||||
GenericValue n(name, internal::StrLen(name), nameAllocator);
|
||||
return AddMember(n, value, allocator);
|
||||
}
|
||||
|
||||
GenericValue& AddMember(const char* name, GenericValue& value, Allocator& allocator) {
|
||||
GenericValue n(name, internal::StrLen(name));
|
||||
return AddMember(n, value, allocator);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
GenericValue& AddMember(const char* name, T value, Allocator& allocator) {
|
||||
GenericValue n(name, internal::StrLen(name));
|
||||
GenericValue v(value);
|
||||
return AddMember(n, v, allocator);
|
||||
}
|
||||
|
||||
//! Remove a member in object by its name.
|
||||
/*! \param name Name of member to be removed.
|
||||
\return Whether the member existed.
|
||||
\note Removing member is implemented by moving the last member. So the ordering of members is changed.
|
||||
*/
|
||||
bool RemoveMember(const Ch* name) {
|
||||
RAPIDJSON_ASSERT(IsObject());
|
||||
if (Member* m = FindMember(name)) {
|
||||
RAPIDJSON_ASSERT(data_.o.size > 0);
|
||||
RAPIDJSON_ASSERT(data_.o.members != 0);
|
||||
|
||||
if (data_.o.size > 1) {
|
||||
// Move the last one to this place
|
||||
Member* last = data_.o.members + (data_.o.size - 1);
|
||||
m->name = last->name;
|
||||
m->value = last->value;
|
||||
}
|
||||
else {
|
||||
// Only one left, just destroy
|
||||
m->name.~GenericValue();
|
||||
m->value.~GenericValue();
|
||||
}
|
||||
--data_.o.size;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
//!@name Array
|
||||
//@{
|
||||
|
||||
//! Set this value as an empty array.
|
||||
GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }
|
||||
|
||||
//! Get the number of elements in array.
|
||||
SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; }
|
||||
|
||||
//! Get the capacity of array.
|
||||
SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; }
|
||||
|
||||
//! Check whether the array is empty.
|
||||
bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; }
|
||||
|
||||
//! Remove all elements in the array.
|
||||
/*! This function do not deallocate memory in the array, i.e. the capacity is unchanged.
|
||||
*/
|
||||
void Clear() {
|
||||
RAPIDJSON_ASSERT(IsArray());
|
||||
for (SizeType i = 0; i < data_.a.size; ++i)
|
||||
data_.a.elements[i].~GenericValue();
|
||||
data_.a.size = 0;
|
||||
}
|
||||
|
||||
//! Get an element from array by index.
|
||||
/*! \param index Zero-based index of element.
|
||||
\note
|
||||
\code
|
||||
Value a(kArrayType);
|
||||
a.PushBack(123);
|
||||
int x = a[0].GetInt(); // Error: operator[ is ambiguous, as 0 also mean a null pointer of const char* type.
|
||||
int y = a[SizeType(0)].GetInt(); // Cast to SizeType will work.
|
||||
int z = a[0u].GetInt(); // This works too.
|
||||
\endcode
|
||||
*/
|
||||
GenericValue& operator[](SizeType index) {
|
||||
RAPIDJSON_ASSERT(IsArray());
|
||||
RAPIDJSON_ASSERT(index < data_.a.size);
|
||||
return data_.a.elements[index];
|
||||
}
|
||||
const GenericValue& operator[](SizeType index) const { return const_cast<GenericValue&>(*this)[index]; }
|
||||
|
||||
//! Element iterator
|
||||
ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements; }
|
||||
ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements + data_.a.size; }
|
||||
ConstValueIterator Begin() const { return const_cast<GenericValue&>(*this).Begin(); }
|
||||
ConstValueIterator End() const { return const_cast<GenericValue&>(*this).End(); }
|
||||
|
||||
//! Request the array to have enough capacity to store elements.
|
||||
/*! \param newCapacity The capacity that the array at least need to have.
|
||||
\param allocator The allocator for allocating memory. It must be the same one use previously.
|
||||
\return The value itself for fluent API.
|
||||
*/
|
||||
GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
|
||||
RAPIDJSON_ASSERT(IsArray());
|
||||
if (newCapacity > data_.a.capacity) {
|
||||
data_.a.elements = (GenericValue*)allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue));
|
||||
data_.a.capacity = newCapacity;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Append a value at the end of the array.
|
||||
/*! \param value The value to be appended.
|
||||
\param allocator The allocator for allocating memory. It must be the same one use previously.
|
||||
\return The value itself for fluent API.
|
||||
\note The ownership of the value will be transfered to this object if success.
|
||||
\note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
|
||||
*/
|
||||
GenericValue& PushBack(GenericValue& value, Allocator& allocator) {
|
||||
RAPIDJSON_ASSERT(IsArray());
|
||||
if (data_.a.size >= data_.a.capacity)
|
||||
Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : data_.a.capacity * 2, allocator);
|
||||
data_.a.elements[data_.a.size++] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
GenericValue& PushBack(T value, Allocator& allocator) {
|
||||
GenericValue v(value);
|
||||
return PushBack(v, allocator);
|
||||
}
|
||||
|
||||
//! Remove the last element in the array.
|
||||
GenericValue& PopBack() {
|
||||
RAPIDJSON_ASSERT(IsArray());
|
||||
RAPIDJSON_ASSERT(!Empty());
|
||||
data_.a.elements[--data_.a.size].~GenericValue();
|
||||
return *this;
|
||||
}
|
||||
//@}
|
||||
|
||||
//!@name Number
|
||||
//@{
|
||||
|
||||
int GetInt() const { RAPIDJSON_ASSERT(flags_ & kIntFlag); return data_.n.i; }
|
||||
unsigned GetUint() const { RAPIDJSON_ASSERT(flags_ & kUintFlag); return data_.n.u; }
|
||||
int64_t GetInt64() const { RAPIDJSON_ASSERT(flags_ & kInt64Flag); return data_.n.i64; }
|
||||
int64_t GetUint64() const { RAPIDJSON_ASSERT(flags_ & kInt64Flag); return data_.n.u64; }
|
||||
|
||||
double GetDouble() const {
|
||||
RAPIDJSON_ASSERT(IsNumber());
|
||||
if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion.
|
||||
if ((flags_ & kIntFlag) != 0) return data_.n.i; // int -> double
|
||||
if ((flags_ & kUintFlag) != 0) return data_.n.u; // unsigned -> double
|
||||
if ((flags_ & kInt64Flag) != 0) return (double)data_.n.i64; // int64_t -> double (may lose precision)
|
||||
RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return (double)data_.n.u64; // uint64_t -> double (may lose precision)
|
||||
}
|
||||
|
||||
GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; }
|
||||
GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; }
|
||||
GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; }
|
||||
GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; }
|
||||
GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; }
|
||||
|
||||
//@}
|
||||
|
||||
//!@name String
|
||||
//@{
|
||||
|
||||
const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return data_.s.str; }
|
||||
|
||||
//! Get the length of string.
|
||||
/*! Since rapidjson permits "\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
|
||||
*/
|
||||
SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return data_.s.length; }
|
||||
|
||||
//! Set this value as a string without copying source string.
|
||||
/*! This version has better performance with supplied length, and also support string containing null character.
|
||||
\param s source string pointer.
|
||||
\param length The length of source string, excluding the trailing null terminator.
|
||||
\return The value itself for fluent API.
|
||||
*/
|
||||
GenericValue& SetString(const Ch* s, SizeType length) { this->~GenericValue(); SetStringRaw(s, length); return *this; }
|
||||
|
||||
//! Set this value as a string without copying source string.
|
||||
/*! \param s source string pointer.
|
||||
\return The value itself for fluent API.
|
||||
*/
|
||||
GenericValue& SetString(const Ch* s) { return SetString(s, internal::StrLen(s)); }
|
||||
|
||||
//! Set this value as a string by copying from source string.
|
||||
/*! This version has better performance with supplied length, and also support string containing null character.
|
||||
\param s source string.
|
||||
\param length The length of source string, excluding the trailing null terminator.
|
||||
\param allocator Allocator for allocating copied buffer. Commonly use document.GetAllocator().
|
||||
\return The value itself for fluent API.
|
||||
*/
|
||||
GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, length, allocator); return *this; }
|
||||
|
||||
//! Set this value as a string by copying from source string.
|
||||
/*! \param s source string.
|
||||
\param allocator Allocator for allocating copied buffer. Commonly use document.GetAllocator().
|
||||
\return The value itself for fluent API.
|
||||
*/
|
||||
GenericValue& SetString(const Ch* s, Allocator& allocator) { SetString(s, internal::StrLen(s), allocator); return *this; }
|
||||
|
||||
//@}
|
||||
|
||||
//! Generate events of this value to a Handler.
|
||||
/*! This function adopts the GoF visitor pattern.
|
||||
Typical usage is to output this JSON value as JSON text via Writer, which is a Handler.
|
||||
It can also be used to deep clone this value via GenericDocument, which is also a Handler.
|
||||
\tparam Handler type of handler.
|
||||
\param handler An object implementing concept Handler.
|
||||
*/
|
||||
template <typename Handler>
|
||||
GenericValue& Accept(Handler& handler) {
|
||||
switch(GetType()) {
|
||||
case kNullType: handler.Null(); break;
|
||||
case kFalseType: handler.Bool(false); break;
|
||||
case kTrueType: handler.Bool(true); break;
|
||||
|
||||
case kObjectType:
|
||||
handler.StartObject();
|
||||
for (Member* m = data_.o.members; m != data_.o.members + data_.o.size; ++m) {
|
||||
handler.String(m->name.data_.s.str, m->name.data_.s.length, false);
|
||||
m->value.Accept(handler);
|
||||
}
|
||||
handler.EndObject(data_.o.size);
|
||||
break;
|
||||
|
||||
case kArrayType:
|
||||
handler.StartArray();
|
||||
for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)
|
||||
v->Accept(handler);
|
||||
handler.EndArray(data_.a.size);
|
||||
break;
|
||||
|
||||
case kStringType:
|
||||
handler.String(data_.s.str, data_.s.length, false);
|
||||
break;
|
||||
|
||||
case kNumberType:
|
||||
if (IsInt()) handler.Int(data_.n.i);
|
||||
else if (IsUint()) handler.Uint(data_.n.u);
|
||||
else if (IsInt64()) handler.Int64(data_.n.i64);
|
||||
else if (IsUint64()) handler.Uint64(data_.n.i64);
|
||||
else handler.Double(data_.n.d);
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename, typename>
|
||||
friend class GenericDocument;
|
||||
|
||||
enum {
|
||||
kBoolFlag = 0x100,
|
||||
kNumberFlag = 0x200,
|
||||
kIntFlag = 0x400,
|
||||
kUintFlag = 0x800,
|
||||
kInt64Flag = 0x1000,
|
||||
kUint64Flag = 0x2000,
|
||||
kDoubleFlag = 0x4000,
|
||||
kStringFlag = 0x100000,
|
||||
kCopyFlag = 0x200000,
|
||||
|
||||
// Initial flags of different types.
|
||||
kNullFlag = kNullType,
|
||||
kTrueFlag = kTrueType | kBoolFlag,
|
||||
kFalseFlag = kFalseType | kBoolFlag,
|
||||
kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag,
|
||||
kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag,
|
||||
kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag,
|
||||
kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag,
|
||||
kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag,
|
||||
kConstStringFlag = kStringType | kStringFlag,
|
||||
kCopyStringFlag = kStringType | kStringFlag | kCopyFlag,
|
||||
kObjectFlag = kObjectType,
|
||||
kArrayFlag = kArrayType,
|
||||
|
||||
kTypeMask = 0xFF // bitwise-and with mask of 0xFF can be optimized by compiler
|
||||
};
|
||||
|
||||
static const SizeType kDefaultArrayCapacity = 16;
|
||||
static const SizeType kDefaultObjectCapacity = 16;
|
||||
|
||||
struct String {
|
||||
const Ch* str;
|
||||
SizeType length;
|
||||
unsigned hashcode; //!< reserved
|
||||
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
|
||||
|
||||
// By using proper binary layout, retrieval of different integer types do not need conversions.
|
||||
union Number {
|
||||
#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN
|
||||
struct {
|
||||
int i;
|
||||
char padding[4];
|
||||
};
|
||||
struct {
|
||||
unsigned u;
|
||||
char padding2[4];
|
||||
};
|
||||
#else
|
||||
struct {
|
||||
char padding[4];
|
||||
int i;
|
||||
};
|
||||
struct {
|
||||
char padding2[4];
|
||||
unsigned u;
|
||||
};
|
||||
#endif
|
||||
int64_t i64;
|
||||
uint64_t u64;
|
||||
double d;
|
||||
}; // 8 bytes
|
||||
|
||||
struct Object {
|
||||
Member* members;
|
||||
SizeType size;
|
||||
SizeType capacity;
|
||||
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
|
||||
|
||||
struct Array {
|
||||
GenericValue<Encoding, Allocator>* elements;
|
||||
SizeType size;
|
||||
SizeType capacity;
|
||||
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
|
||||
|
||||
union Data {
|
||||
String s;
|
||||
Number n;
|
||||
Object o;
|
||||
Array a;
|
||||
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
|
||||
|
||||
//! Find member by name.
|
||||
Member* FindMember(const Ch* name) {
|
||||
RAPIDJSON_ASSERT(name);
|
||||
RAPIDJSON_ASSERT(IsObject());
|
||||
|
||||
Object& o = data_.o;
|
||||
for (Member* member = o.members; member != data_.o.members + data_.o.size; ++member)
|
||||
if (name[member->name.data_.s.length] == '\0' && memcmp(member->name.data_.s.str, name, member->name.data_.s.length * sizeof(Ch)) == 0)
|
||||
return member;
|
||||
|
||||
return 0;
|
||||
}
|
||||
const Member* FindMember(const Ch* name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
|
||||
|
||||
// Initialize this value as array with initial data, without calling destructor.
|
||||
void SetArrayRaw(GenericValue* values, SizeType count, Allocator& alloctaor) {
|
||||
flags_ = kArrayFlag;
|
||||
data_.a.elements = (GenericValue*)alloctaor.Malloc(count * sizeof(GenericValue));
|
||||
memcpy(data_.a.elements, values, count * sizeof(GenericValue));
|
||||
data_.a.size = data_.a.capacity = count;
|
||||
}
|
||||
|
||||
//! Initialize this value as object with initial data, without calling destructor.
|
||||
void SetObjectRaw(Member* members, SizeType count, Allocator& alloctaor) {
|
||||
flags_ = kObjectFlag;
|
||||
data_.o.members = (Member*)alloctaor.Malloc(count * sizeof(Member));
|
||||
memcpy(data_.o.members, members, count * sizeof(Member));
|
||||
data_.o.size = data_.o.capacity = count;
|
||||
}
|
||||
|
||||
//! Initialize this value as constant string, without calling destructor.
|
||||
void SetStringRaw(const Ch* s, SizeType length) {
|
||||
RAPIDJSON_ASSERT(s != NULL);
|
||||
flags_ = kConstStringFlag;
|
||||
data_.s.str = s;
|
||||
data_.s.length = length;
|
||||
}
|
||||
|
||||
//! Initialize this value as copy string with initial data, without calling destructor.
|
||||
void SetStringRaw(const Ch* s, SizeType length, Allocator& allocator) {
|
||||
RAPIDJSON_ASSERT(s != NULL);
|
||||
flags_ = kCopyStringFlag;
|
||||
data_.s.str = (char *)allocator.Malloc(length + 1);
|
||||
data_.s.length = length;
|
||||
memcpy((void*)data_.s.str, s, length);
|
||||
((char*)data_.s.str)[length] = '\0';
|
||||
}
|
||||
|
||||
//! Assignment without calling destructor
|
||||
void RawAssign(GenericValue& rhs) {
|
||||
memcpy(this, &rhs, sizeof(GenericValue));
|
||||
rhs.flags_ = kNullFlag;
|
||||
}
|
||||
|
||||
Data data_;
|
||||
unsigned flags_;
|
||||
};
|
||||
#pragma pack (pop)
|
||||
|
||||
//! Value with UTF8 encoding.
|
||||
typedef GenericValue<UTF8<> > Value;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GenericDocument
|
||||
|
||||
//! A document for parsing JSON text as DOM.
|
||||
/*!
|
||||
\implements Handler
|
||||
\tparam Encoding encoding for both parsing and string storage.
|
||||
\tparam Alloactor allocator for allocating memory for the DOM, and the stack during parsing.
|
||||
*/
|
||||
template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
|
||||
class GenericDocument : public GenericValue<Encoding, Allocator> {
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
|
||||
typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of the document.
|
||||
typedef Allocator AllocatorType; //!< Allocator type from template parameter.
|
||||
|
||||
//! Constructor
|
||||
/*! \param allocator Optional allocator for allocating stack memory.
|
||||
\param stackCapacity Initial capacity of stack in bytes.
|
||||
*/
|
||||
GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseError_(0), errorOffset_(0) {}
|
||||
|
||||
//! Parse JSON text from an input stream.
|
||||
/*! \tparam parseFlags Combination of ParseFlag.
|
||||
\param stream Input stream to be parsed.
|
||||
\return The document itself for fluent API.
|
||||
*/
|
||||
template <unsigned parseFlags, typename Stream>
|
||||
GenericDocument& ParseStream(Stream& stream) {
|
||||
ValueType::SetNull(); // Remove existing root if exist
|
||||
GenericReader<Encoding> reader;
|
||||
if (reader.Parse<parseFlags>(stream, *this)) {
|
||||
RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
|
||||
RawAssign(*stack_.template Pop<ValueType>(1));
|
||||
parseError_ = 0;
|
||||
errorOffset_ = 0;
|
||||
}
|
||||
else {
|
||||
parseError_ = reader.GetParseError();
|
||||
errorOffset_ = reader.GetErrorOffset();
|
||||
ClearStack();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Parse JSON text from a mutable string.
|
||||
/*! \tparam parseFlags Combination of ParseFlag.
|
||||
\param str Mutable zero-terminated string to be parsed.
|
||||
\return The document itself for fluent API.
|
||||
*/
|
||||
template <unsigned parseFlags>
|
||||
GenericDocument& ParseInsitu(Ch* str) {
|
||||
GenericInsituStringStream<Encoding> s(str);
|
||||
return ParseStream<parseFlags | kParseInsituFlag>(s);
|
||||
}
|
||||
|
||||
//! Parse JSON text from a read-only string.
|
||||
/*! \tparam parseFlags Combination of ParseFlag (must not contain kParseInsituFlag).
|
||||
\param str Read-only zero-terminated string to be parsed.
|
||||
*/
|
||||
template <unsigned parseFlags>
|
||||
GenericDocument& Parse(const Ch* str) {
|
||||
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
|
||||
GenericStringStream<Encoding> s(str);
|
||||
return ParseStream<parseFlags>(s);
|
||||
}
|
||||
|
||||
//! Whether a parse error was occured in the last parsing.
|
||||
bool HasParseError() const { return parseError_ != 0; }
|
||||
|
||||
//! Get the message of parsing error.
|
||||
const char* GetParseError() const { return parseError_; }
|
||||
|
||||
//! Get the offset in character of the parsing error.
|
||||
size_t GetErrorOffset() const { return errorOffset_; }
|
||||
|
||||
//! Get the allocator of this document.
|
||||
Allocator& GetAllocator() { return stack_.GetAllocator(); }
|
||||
|
||||
//! Get the capacity of stack in bytes.
|
||||
size_t GetStackCapacity() const { return stack_.GetCapacity(); }
|
||||
|
||||
private:
|
||||
friend class GenericReader<Encoding>; // for Reader to call the following private handler functions
|
||||
|
||||
// Implementation of Handler
|
||||
void Null() { new (stack_.template Push<ValueType>()) ValueType(); }
|
||||
void Bool(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); }
|
||||
void Int(int i) { new (stack_.template Push<ValueType>()) ValueType(i); }
|
||||
void Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i); }
|
||||
void Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); }
|
||||
void Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); }
|
||||
void Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); }
|
||||
|
||||
void String(const Ch* str, SizeType length, bool copy) {
|
||||
if (copy)
|
||||
new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
|
||||
else
|
||||
new (stack_.template Push<ValueType>()) ValueType(str, length);
|
||||
}
|
||||
|
||||
void StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); }
|
||||
|
||||
void EndObject(SizeType memberCount) {
|
||||
typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);
|
||||
stack_.template Top<ValueType>()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator());
|
||||
}
|
||||
|
||||
void StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArrayType); }
|
||||
|
||||
void EndArray(SizeType elementCount) {
|
||||
ValueType* elements = stack_.template Pop<ValueType>(elementCount);
|
||||
stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, GetAllocator());
|
||||
}
|
||||
|
||||
void ClearStack() {
|
||||
if (Allocator::kNeedFree)
|
||||
while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects)
|
||||
(stack_.template Pop<ValueType>(1))->~ValueType();
|
||||
else
|
||||
stack_.Clear();
|
||||
}
|
||||
|
||||
static const size_t kDefaultStackCapacity = 1024;
|
||||
internal::Stack<Allocator> stack_;
|
||||
const char* parseError_;
|
||||
size_t errorOffset_;
|
||||
};
|
||||
|
||||
typedef GenericDocument<UTF8<> > Document;
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_DOCUMENT_H_
|
46
include/rapidjson/filestream.h
Normal file
46
include/rapidjson/filestream.h
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef RAPIDJSON_FILESTREAM_H_
|
||||
#define RAPIDJSON_FILESTREAM_H_
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! Wrapper of C file stream for input or output.
|
||||
/*!
|
||||
This simple wrapper does not check the validity of the stream.
|
||||
\implements Stream
|
||||
*/
|
||||
class FileStream {
|
||||
public:
|
||||
typedef char Ch; //!< Character type. Only support char.
|
||||
|
||||
FileStream(FILE* fp) : fp_(fp), count_(0) { Read(); }
|
||||
char Peek() const { return current_; }
|
||||
char Take() { char c = current_; Read(); return c; }
|
||||
size_t Tell() const { return count_; }
|
||||
void Put(char c) { fputc(c, fp_); }
|
||||
|
||||
// Not implemented
|
||||
char* PutBegin() { return 0; }
|
||||
size_t PutEnd(char*) { return 0; }
|
||||
|
||||
private:
|
||||
void Read() {
|
||||
RAPIDJSON_ASSERT(fp_ != 0);
|
||||
int c = fgetc(fp_);
|
||||
if (c != EOF) {
|
||||
current_ = (char)c;
|
||||
count_++;
|
||||
}
|
||||
else
|
||||
current_ = '\0';
|
||||
}
|
||||
|
||||
FILE* fp_;
|
||||
char current_;
|
||||
size_t count_;
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
54
include/rapidjson/internal/pow10.h
Normal file
54
include/rapidjson/internal/pow10.h
Normal file
@ -0,0 +1,54 @@
|
||||
#ifndef RAPIDJSON_POW10_
|
||||
#define RAPIDJSON_POW10_
|
||||
|
||||
namespace rapidjson {
|
||||
namespace internal {
|
||||
|
||||
//! Computes integer powers of 10 in double (10.0^n).
|
||||
/*! This function uses lookup table for fast and accurate results.
|
||||
\param n positive/negative exponent. Must <= 308.
|
||||
\return 10.0^n
|
||||
*/
|
||||
inline double Pow10(int n) {
|
||||
static const double e[] = { // 1e-308...1e308: 617 * 8 bytes = 4936 bytes
|
||||
1e-308,1e-307,1e-306,1e-305,1e-304,1e-303,1e-302,1e-301,1e-300,
|
||||
1e-299,1e-298,1e-297,1e-296,1e-295,1e-294,1e-293,1e-292,1e-291,1e-290,1e-289,1e-288,1e-287,1e-286,1e-285,1e-284,1e-283,1e-282,1e-281,1e-280,
|
||||
1e-279,1e-278,1e-277,1e-276,1e-275,1e-274,1e-273,1e-272,1e-271,1e-270,1e-269,1e-268,1e-267,1e-266,1e-265,1e-264,1e-263,1e-262,1e-261,1e-260,
|
||||
1e-259,1e-258,1e-257,1e-256,1e-255,1e-254,1e-253,1e-252,1e-251,1e-250,1e-249,1e-248,1e-247,1e-246,1e-245,1e-244,1e-243,1e-242,1e-241,1e-240,
|
||||
1e-239,1e-238,1e-237,1e-236,1e-235,1e-234,1e-233,1e-232,1e-231,1e-230,1e-229,1e-228,1e-227,1e-226,1e-225,1e-224,1e-223,1e-222,1e-221,1e-220,
|
||||
1e-219,1e-218,1e-217,1e-216,1e-215,1e-214,1e-213,1e-212,1e-211,1e-210,1e-209,1e-208,1e-207,1e-206,1e-205,1e-204,1e-203,1e-202,1e-201,1e-200,
|
||||
1e-199,1e-198,1e-197,1e-196,1e-195,1e-194,1e-193,1e-192,1e-191,1e-190,1e-189,1e-188,1e-187,1e-186,1e-185,1e-184,1e-183,1e-182,1e-181,1e-180,
|
||||
1e-179,1e-178,1e-177,1e-176,1e-175,1e-174,1e-173,1e-172,1e-171,1e-170,1e-169,1e-168,1e-167,1e-166,1e-165,1e-164,1e-163,1e-162,1e-161,1e-160,
|
||||
1e-159,1e-158,1e-157,1e-156,1e-155,1e-154,1e-153,1e-152,1e-151,1e-150,1e-149,1e-148,1e-147,1e-146,1e-145,1e-144,1e-143,1e-142,1e-141,1e-140,
|
||||
1e-139,1e-138,1e-137,1e-136,1e-135,1e-134,1e-133,1e-132,1e-131,1e-130,1e-129,1e-128,1e-127,1e-126,1e-125,1e-124,1e-123,1e-122,1e-121,1e-120,
|
||||
1e-119,1e-118,1e-117,1e-116,1e-115,1e-114,1e-113,1e-112,1e-111,1e-110,1e-109,1e-108,1e-107,1e-106,1e-105,1e-104,1e-103,1e-102,1e-101,1e-100,
|
||||
1e-99, 1e-98, 1e-97, 1e-96, 1e-95, 1e-94, 1e-93, 1e-92, 1e-91, 1e-90, 1e-89, 1e-88, 1e-87, 1e-86, 1e-85, 1e-84, 1e-83, 1e-82, 1e-81, 1e-80,
|
||||
1e-79, 1e-78, 1e-77, 1e-76, 1e-75, 1e-74, 1e-73, 1e-72, 1e-71, 1e-70, 1e-69, 1e-68, 1e-67, 1e-66, 1e-65, 1e-64, 1e-63, 1e-62, 1e-61, 1e-60,
|
||||
1e-59, 1e-58, 1e-57, 1e-56, 1e-55, 1e-54, 1e-53, 1e-52, 1e-51, 1e-50, 1e-49, 1e-48, 1e-47, 1e-46, 1e-45, 1e-44, 1e-43, 1e-42, 1e-41, 1e-40,
|
||||
1e-39, 1e-38, 1e-37, 1e-36, 1e-35, 1e-34, 1e-33, 1e-32, 1e-31, 1e-30, 1e-29, 1e-28, 1e-27, 1e-26, 1e-25, 1e-24, 1e-23, 1e-22, 1e-21, 1e-20,
|
||||
1e-19, 1e-18, 1e-17, 1e-16, 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e+0,
|
||||
1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20,
|
||||
1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
|
||||
1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
|
||||
1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
|
||||
1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
|
||||
1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
|
||||
1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
|
||||
1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
|
||||
1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
|
||||
1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
|
||||
1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
|
||||
1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
|
||||
1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
|
||||
1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
|
||||
1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
|
||||
1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
|
||||
};
|
||||
RAPIDJSON_ASSERT(n <= 308);
|
||||
return n < -308 ? 0.0 : e[n + 308];
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_POW10_
|
82
include/rapidjson/internal/stack.h
Normal file
82
include/rapidjson/internal/stack.h
Normal file
@ -0,0 +1,82 @@
|
||||
#ifndef RAPIDJSON_INTERNAL_STACK_H_
|
||||
#define RAPIDJSON_INTERNAL_STACK_H_
|
||||
|
||||
namespace rapidjson {
|
||||
namespace internal {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Stack
|
||||
|
||||
//! A type-unsafe stack for storing different types of data.
|
||||
/*! \tparam Allocator Allocator for allocating stack memory.
|
||||
*/
|
||||
template <typename Allocator>
|
||||
class Stack {
|
||||
public:
|
||||
Stack(Allocator* allocator, size_t stack_capacity) : allocator_(allocator), own_allocator_(0), stack_(0), stack_top_(0), stack_end_(0), stack_capacity_(stack_capacity) {
|
||||
RAPIDJSON_ASSERT(stack_capacity_ > 0);
|
||||
if (!allocator_)
|
||||
own_allocator_ = allocator_ = new Allocator();
|
||||
stack_top_ = stack_ = (char*)allocator_->Malloc(stack_capacity_);
|
||||
stack_end_ = stack_ + stack_capacity_;
|
||||
}
|
||||
|
||||
~Stack() {
|
||||
Allocator::Free(stack_);
|
||||
delete own_allocator_; // Only delete if it is owned by the stack
|
||||
}
|
||||
|
||||
void Clear() { /*stack_top_ = 0;*/ stack_top_ = stack_; }
|
||||
|
||||
template<typename T>
|
||||
T* Push(size_t count = 1) {
|
||||
// Expand the stack if needed
|
||||
if (stack_top_ + sizeof(T) * count >= stack_end_) {
|
||||
size_t new_capacity = stack_capacity_ * 2;
|
||||
size_t size = GetSize();
|
||||
size_t new_size = GetSize() + sizeof(T) * count;
|
||||
if (new_capacity < new_size)
|
||||
new_capacity = new_size;
|
||||
stack_ = (char*)allocator_->Realloc(stack_, stack_capacity_, new_capacity);
|
||||
stack_capacity_ = new_capacity;
|
||||
stack_top_ = stack_ + size;
|
||||
stack_end_ = stack_ + stack_capacity_;
|
||||
}
|
||||
T* ret = (T*)stack_top_;
|
||||
stack_top_ += sizeof(T) * count;
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Pop(size_t count) {
|
||||
RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
|
||||
stack_top_ -= count * sizeof(T);
|
||||
return (T*)stack_top_;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Top() {
|
||||
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
||||
return (T*)(stack_top_ - sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Bottom() { return (T*)stack_; }
|
||||
|
||||
Allocator& GetAllocator() { return *allocator_; }
|
||||
size_t GetSize() const { /*return stack_top_;*/ return stack_top_ - stack_; }
|
||||
size_t GetCapacity() const { return stack_capacity_; }
|
||||
|
||||
private:
|
||||
Allocator* allocator_;
|
||||
Allocator* own_allocator_;
|
||||
char *stack_;
|
||||
char *stack_top_;
|
||||
char *stack_end_;
|
||||
size_t stack_capacity_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_STACK_H_
|
24
include/rapidjson/internal/strfunc.h
Normal file
24
include/rapidjson/internal/strfunc.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
#define RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
|
||||
namespace rapidjson {
|
||||
namespace internal {
|
||||
|
||||
//! Custom strlen() which works on different character types.
|
||||
/*! \tparam Ch Character type (e.g. char, wchar_t, short)
|
||||
\param s Null-terminated input string.
|
||||
\return Number of characters in the string.
|
||||
\note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
|
||||
*/
|
||||
template <typename Ch>
|
||||
inline SizeType StrLen(const Ch* s) {
|
||||
const Ch* p = s;
|
||||
while (*p != '\0')
|
||||
++p;
|
||||
return SizeType(p - s);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
|
152
include/rapidjson/prettywriter.h
Normal file
152
include/rapidjson/prettywriter.h
Normal file
@ -0,0 +1,152 @@
|
||||
#ifndef RAPIDJSON_PRETTYWRITER_H_
|
||||
#define RAPIDJSON_PRETTYWRITER_H_
|
||||
|
||||
#include "writer.h"
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! Writer with indentation and spacing.
|
||||
/*!
|
||||
\tparam Stream Type of ouptut stream.
|
||||
\tparam Encoding Encoding of both source strings and output.
|
||||
\tparam Allocator Type of allocator for allocating memory of stack.
|
||||
*/
|
||||
template<typename Stream, typename Encoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
|
||||
class PrettyWriter : public Writer<Stream, Encoding, Allocator> {
|
||||
public:
|
||||
typedef Writer<Stream, Encoding, Allocator> Base;
|
||||
typedef typename Base::Ch Ch;
|
||||
|
||||
//! Constructor
|
||||
/*! \param stream Output stream.
|
||||
\param allocator User supplied allocator. If it is null, it will create a private one.
|
||||
\param levelDepth Initial capacity of
|
||||
*/
|
||||
PrettyWriter(Stream& stream, Allocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
|
||||
Base(stream, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
|
||||
|
||||
//! Set custom indentation.
|
||||
/*! \param indentChar Character for indentation. Must be whitespace character (' ', '\t', '\n', '\r').
|
||||
\param indentCharCount Number of indent characters for each indentation level.
|
||||
\note The default indentation is 4 spaces.
|
||||
*/
|
||||
PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
|
||||
RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
|
||||
indentChar_ = indentChar;
|
||||
indentCharCount_ = indentCharCount;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//@name Implementation of Handler.
|
||||
//@{
|
||||
|
||||
PrettyWriter& Null() { PrettyPrefix(kNullType); Base::WriteNull(); return *this; }
|
||||
PrettyWriter& Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); Base::WriteBool(b); return *this; }
|
||||
PrettyWriter& Int(int i) { PrettyPrefix(kNumberType); Base::WriteInt(i); return *this; }
|
||||
PrettyWriter& Uint(unsigned u) { PrettyPrefix(kNumberType); Base::WriteUint(u); return *this; }
|
||||
PrettyWriter& Int64(int64_t i64) { PrettyPrefix(kNumberType); Base::WriteInt64(i64); return *this; }
|
||||
PrettyWriter& Uint64(uint64_t u64) { PrettyPrefix(kNumberType); Base::WriteUint64(u64); return *this; }
|
||||
PrettyWriter& Double(double d) { PrettyPrefix(kNumberType); Base::WriteDouble(d); return *this; }
|
||||
|
||||
PrettyWriter& String(const Ch* str, SizeType length, bool copy = false) {
|
||||
PrettyPrefix(kStringType);
|
||||
Base::WriteString(str, length);
|
||||
return *this;
|
||||
}
|
||||
|
||||
PrettyWriter& StartObject() {
|
||||
PrettyPrefix(kObjectType);
|
||||
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
|
||||
Base::WriteStartObject();
|
||||
return *this;
|
||||
}
|
||||
|
||||
PrettyWriter& EndObject(SizeType memberCount = 0) {
|
||||
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
|
||||
RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
|
||||
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
|
||||
|
||||
if (!empty) {
|
||||
Base::stream_.Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
Base::WriteEndObject();
|
||||
return *this;
|
||||
}
|
||||
|
||||
PrettyWriter& StartArray() {
|
||||
PrettyPrefix(kArrayType);
|
||||
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
|
||||
Base::WriteStartArray();
|
||||
return *this;
|
||||
}
|
||||
|
||||
PrettyWriter& EndArray(SizeType memberCount = 0) {
|
||||
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
|
||||
RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
|
||||
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
|
||||
|
||||
if (!empty) {
|
||||
Base::stream_.Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
Base::WriteEndArray();
|
||||
return *this;
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
//! Simpler but slower overload.
|
||||
PrettyWriter& String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
||||
|
||||
protected:
|
||||
void PrettyPrefix(Type type) {
|
||||
if (Base::level_stack_.GetSize() != 0) { // this value is not at root
|
||||
typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
|
||||
|
||||
if (level->inArray) {
|
||||
if (level->valueCount > 0) {
|
||||
Base::stream_.Put(','); // add comma if it is not the first element in array
|
||||
Base::stream_.Put('\n');
|
||||
}
|
||||
else
|
||||
Base::stream_.Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
else { // in object
|
||||
if (level->valueCount > 0) {
|
||||
if (level->valueCount % 2 == 0) {
|
||||
Base::stream_.Put(',');
|
||||
Base::stream_.Put('\n');
|
||||
}
|
||||
else {
|
||||
Base::stream_.Put(':');
|
||||
Base::stream_.Put(' ');
|
||||
}
|
||||
}
|
||||
else
|
||||
Base::stream_.Put('\n');
|
||||
|
||||
if (level->valueCount % 2 == 0)
|
||||
WriteIndent();
|
||||
}
|
||||
if (!level->inArray && level->valueCount % 2 == 0)
|
||||
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
|
||||
level->valueCount++;
|
||||
}
|
||||
else
|
||||
RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
|
||||
}
|
||||
|
||||
void WriteIndent() {
|
||||
size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
|
||||
PutN(Base::stream_, indentChar_, count);
|
||||
}
|
||||
|
||||
Ch indentChar_;
|
||||
unsigned indentCharCount_;
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_RAPIDJSON_H_
|
512
include/rapidjson/rapidjson.h
Normal file
512
include/rapidjson/rapidjson.h
Normal file
@ -0,0 +1,512 @@
|
||||
#ifndef RAPIDJSON_RAPIDJSON_H_
|
||||
#define RAPIDJSON_RAPIDJSON_H_
|
||||
|
||||
// Copyright (c) 2011 Milo Yip (miloyip@gmail.com)
|
||||
// Version 0.1
|
||||
|
||||
#include <cstdlib> // malloc(), realloc(), free()
|
||||
#include <cstring> // memcpy()
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_NO_INT64DEFINE
|
||||
|
||||
// Here defines int64_t and uint64_t types in global namespace.
|
||||
// If user have their own definition, can define RAPIDJSON_NO_INT64DEFINE to disable this.
|
||||
#ifndef RAPIDJSON_NO_INT64DEFINE
|
||||
#ifdef _MSC_VER
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#else
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
#endif // RAPIDJSON_NO_INT64TYPEDEF
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ENDIAN
|
||||
#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine
|
||||
#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine
|
||||
|
||||
//! Endianness of the machine.
|
||||
/*! GCC provided macro for detecting endianness of the target machine. But other
|
||||
compilers may not have this. User can define RAPIDJSON_ENDIAN to either
|
||||
RAPIDJSON_LITTLEENDIAN or RAPIDJSON_BIGENDIAN.
|
||||
*/
|
||||
#ifndef RAPIDJSON_ENDIAN
|
||||
#ifdef __BYTE_ORDER__
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||
#else
|
||||
#define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
||||
#endif // __BYTE_ORDER__
|
||||
#else
|
||||
#define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN // Assumes little endian otherwise.
|
||||
#endif
|
||||
#endif // RAPIDJSON_ENDIAN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD
|
||||
|
||||
// Enable SSE2 optimization.
|
||||
//#define RAPIDJSON_SSE2
|
||||
|
||||
// Enable SSE4.2 optimization.
|
||||
//#define RAPIDJSON_SSE42
|
||||
|
||||
#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
|
||||
#define RAPIDJSON_SIMD
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_NO_SIZETYPEDEFINE
|
||||
|
||||
#ifndef RAPIDJSON_NO_SIZETYPEDEFINE
|
||||
namespace rapidjson {
|
||||
//! Use 32-bit array/string indices even for 64-bit platform, instead of using size_t.
|
||||
/*! User may override the SizeType by defining RAPIDJSON_NO_SIZETYPEDEFINE.
|
||||
*/
|
||||
typedef unsigned SizeType;
|
||||
} // namespace rapidjson
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ASSERT
|
||||
|
||||
//! Assertion.
|
||||
/*! By default, rapidjson uses C assert() for assertion.
|
||||
User can override it by defining RAPIDJSON_ASSERT(x) macro.
|
||||
*/
|
||||
#ifndef RAPIDJSON_ASSERT
|
||||
#include <cassert>
|
||||
#define RAPIDJSON_ASSERT(x) assert(x)
|
||||
#endif // RAPIDJSON_ASSERT
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Allocator
|
||||
|
||||
/*! \class rapidjson::Allocator
|
||||
\brief Concept for allocating, resizing and freeing memory block.
|
||||
|
||||
Note that Malloc() and Realloc() are non-static but Free() is static.
|
||||
|
||||
So if an allocator need to support Free(), it needs to put its pointer in
|
||||
the header of memory block.
|
||||
|
||||
\code
|
||||
concept Allocator {
|
||||
static const bool kNeedFree; //!< Whether this allocator needs to call Free().
|
||||
|
||||
// Allocate a memory block.
|
||||
// \param size of the memory block in bytes.
|
||||
// \returns pointer to the memory block.
|
||||
void* Malloc(size_t size);
|
||||
|
||||
// Resize a memory block.
|
||||
// \param originalPtr The pointer to current memory block. Null pointer is permitted.
|
||||
// \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
|
||||
// \param newSize the new size in bytes.
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
|
||||
|
||||
// Free a memory block.
|
||||
// \param pointer to the memory block. Null pointer is permitted.
|
||||
static void Free(void *ptr);
|
||||
};
|
||||
\endcode
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CrtAllocator
|
||||
|
||||
//! C-runtime library allocator.
|
||||
/*! This class is just wrapper for standard C library memory routines.
|
||||
\implements Allocator
|
||||
*/
|
||||
class CrtAllocator {
|
||||
public:
|
||||
static const bool kNeedFree = true;
|
||||
void* Malloc(size_t size) { return malloc(size); }
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { return realloc(originalPtr, newSize); }
|
||||
static void Free(void *ptr) { free(ptr); }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MemoryPoolAllocator
|
||||
|
||||
//! Default memory allocator used by the parser and DOM.
|
||||
/*! This allocator allocate memory blocks from pre-allocated memory chunks.
|
||||
|
||||
It does not free memory blocks. And Realloc() only allocate new memory.
|
||||
|
||||
The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
|
||||
|
||||
User may also supply a buffer as the first chunk.
|
||||
|
||||
If the user-buffer is full then additional chunks are allocated by BaseAllocator.
|
||||
|
||||
The user-buffer is not deallocated by this allocator.
|
||||
|
||||
\tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
|
||||
\implements Allocator
|
||||
*/
|
||||
template <typename BaseAllocator = CrtAllocator>
|
||||
class MemoryPoolAllocator {
|
||||
public:
|
||||
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
|
||||
|
||||
//! Constructor with chunkSize.
|
||||
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||
\param baseAllocator The allocator for allocating memory chunks.
|
||||
*/
|
||||
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||
{
|
||||
if (!baseAllocator_)
|
||||
ownBaseAllocator_ = baseAllocator_ = new BaseAllocator();
|
||||
AddChunk(chunk_capacity_);
|
||||
}
|
||||
|
||||
//! Constructor with user-supplied buffer.
|
||||
/*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
|
||||
|
||||
The user buffer will not be deallocated when this allocator is destructed.
|
||||
|
||||
\param buffer User supplied buffer.
|
||||
\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
|
||||
\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||
\param baseAllocator The allocator for allocating memory chunks.
|
||||
*/
|
||||
MemoryPoolAllocator(char *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||
{
|
||||
RAPIDJSON_ASSERT(buffer != 0);
|
||||
RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
|
||||
chunkHead_ = (ChunkHeader*)buffer;
|
||||
chunkHead_->capacity = size - sizeof(ChunkHeader);
|
||||
chunkHead_->size = 0;
|
||||
chunkHead_->next = 0;
|
||||
}
|
||||
|
||||
//! Destructor.
|
||||
/*! This deallocates all memory chunks, excluding the user-supplied buffer.
|
||||
*/
|
||||
~MemoryPoolAllocator() {
|
||||
Clear();
|
||||
delete ownBaseAllocator_;
|
||||
}
|
||||
|
||||
//! Deallocates all memory chunks, excluding the user-supplied buffer.
|
||||
void Clear() {
|
||||
while(chunkHead_ != 0 && chunkHead_ != (ChunkHeader *)userBuffer_) {
|
||||
ChunkHeader* next = chunkHead_->next;
|
||||
baseAllocator_->Free(chunkHead_);
|
||||
chunkHead_ = next;
|
||||
}
|
||||
}
|
||||
|
||||
//! Computes the total capacity of allocated memory chunks.
|
||||
/*! \return total capacity in bytes.
|
||||
*/
|
||||
size_t Capacity() {
|
||||
size_t capacity = 0;
|
||||
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||
capacity += c->capacity;
|
||||
return capacity;
|
||||
}
|
||||
|
||||
//! Computes the memory blocks allocated.
|
||||
/*! \return total used bytes.
|
||||
*/
|
||||
size_t Size() {
|
||||
size_t size = 0;
|
||||
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||
size += c->size;
|
||||
return size;
|
||||
}
|
||||
|
||||
//! Allocates a memory block. (concept Allocator)
|
||||
void* Malloc(size_t size) {
|
||||
if (chunkHead_->size + size > chunkHead_->capacity)
|
||||
AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
|
||||
|
||||
char *buffer = (char *)(chunkHead_ + 1) + chunkHead_->size;
|
||||
chunkHead_->size += size;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
//! Resizes a memory block (concept Allocator)
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
|
||||
if (originalPtr == 0)
|
||||
return Malloc(newSize);
|
||||
|
||||
// Do not shrink if new size is smaller than original
|
||||
if (originalSize >= newSize)
|
||||
return originalPtr;
|
||||
|
||||
// Simply expand it if it is the last allocation and there is sufficient space
|
||||
if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) {
|
||||
size_t increment = newSize - originalSize;
|
||||
if (chunkHead_->size + increment <= chunkHead_->capacity) {
|
||||
chunkHead_->size += increment;
|
||||
return originalPtr;
|
||||
}
|
||||
}
|
||||
|
||||
// Realloc process: allocate and copy memory, do not free original buffer.
|
||||
void* newBuffer = Malloc(newSize);
|
||||
RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly.
|
||||
return memcpy(newBuffer, originalPtr, originalSize);
|
||||
}
|
||||
|
||||
//! Frees a memory block (concept Allocator)
|
||||
static void Free(void *ptr) {} // Do nothing
|
||||
|
||||
private:
|
||||
//! Creates a new chunk.
|
||||
/*! \param capacity Capacity of the chunk in bytes.
|
||||
*/
|
||||
void AddChunk(size_t capacity) {
|
||||
ChunkHeader* chunk = (ChunkHeader*)baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity);
|
||||
chunk->capacity = capacity;
|
||||
chunk->size = 0;
|
||||
chunk->next = chunkHead_;
|
||||
chunkHead_ = chunk;
|
||||
}
|
||||
|
||||
static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
|
||||
|
||||
//! Chunk header for perpending to each chunk.
|
||||
/*! Chunks are stored as a singly linked list.
|
||||
*/
|
||||
struct ChunkHeader {
|
||||
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
|
||||
size_t size; //!< Current size of allocated memory in bytes.
|
||||
ChunkHeader *next; //!< Next chunk in the linked list.
|
||||
};
|
||||
|
||||
ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
|
||||
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
|
||||
char *userBuffer_; //!< User supplied buffer.
|
||||
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
|
||||
BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Encoding
|
||||
|
||||
/*! \class rapidjson::Encoding
|
||||
\brief Concept for encoding of Unicode characters.
|
||||
|
||||
\code
|
||||
concept Encoding {
|
||||
typename Ch; //! Type of character.
|
||||
|
||||
//! \brief Encode a Unicode codepoint to a buffer.
|
||||
//! \param buffer pointer to destination buffer to store the result. It should have sufficient size of encoding one character.
|
||||
//! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
|
||||
//! \returns the pointer to the next character after the encoded data.
|
||||
static Ch* Encode(Ch *buffer, unsigned codepoint);
|
||||
};
|
||||
\endcode
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// UTF8
|
||||
|
||||
//! UTF-8 encoding.
|
||||
/*! http://en.wikipedia.org/wiki/UTF-8
|
||||
\tparam CharType Type for storing 8-bit UTF-8 data. Default is char.
|
||||
\implements Encoding
|
||||
*/
|
||||
template<typename CharType = char>
|
||||
struct UTF8 {
|
||||
typedef CharType Ch;
|
||||
|
||||
static Ch* Encode(Ch *buffer, unsigned codepoint) {
|
||||
if (codepoint <= 0x7F)
|
||||
*buffer++ = codepoint & 0xFF;
|
||||
else if (codepoint <= 0x7FF) {
|
||||
*buffer++ = 0xC0 | ((codepoint >> 6) & 0xFF);
|
||||
*buffer++ = 0x80 | ((codepoint & 0x3F));
|
||||
}
|
||||
else if (codepoint <= 0xFFFF) {
|
||||
*buffer++ = 0xE0 | ((codepoint >> 12) & 0xFF);
|
||||
*buffer++ = 0x80 | ((codepoint >> 6) & 0x3F);
|
||||
*buffer++ = 0x80 | (codepoint & 0x3F);
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
*buffer++ = 0xF0 | ((codepoint >> 18) & 0xFF);
|
||||
*buffer++ = 0x80 | ((codepoint >> 12) & 0x3F);
|
||||
*buffer++ = 0x80 | ((codepoint >> 6) & 0x3F);
|
||||
*buffer++ = 0x80 | (codepoint & 0x3F);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// UTF16
|
||||
|
||||
//! UTF-16 encoding.
|
||||
/*! http://en.wikipedia.org/wiki/UTF-16
|
||||
\tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
|
||||
\implements Encoding
|
||||
*/
|
||||
template<typename CharType = wchar_t>
|
||||
struct UTF16 {
|
||||
typedef CharType Ch;
|
||||
|
||||
static Ch* Encode(Ch* buffer, unsigned codepoint) {
|
||||
if (codepoint <= 0xFFFF) {
|
||||
RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
|
||||
*buffer++ = codepoint;
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
unsigned v = codepoint - 0x10000;
|
||||
*buffer++ = (v >> 10) + 0xD800;
|
||||
*buffer++ = (v & 0x3FF) + 0xDC00;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// UTF32
|
||||
|
||||
//! UTF-32 encoding.
|
||||
/*! http://en.wikipedia.org/wiki/UTF-32
|
||||
\tparam Ch Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
|
||||
\implements Encoding
|
||||
*/
|
||||
template<typename CharType = unsigned>
|
||||
struct UTF32 {
|
||||
typedef CharType Ch;
|
||||
|
||||
static Ch *Encode(Ch* buffer, unsigned codepoint) {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
*buffer++ = codepoint;
|
||||
return buffer;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Stream
|
||||
|
||||
/*! \class rapidjson::Stream
|
||||
\brief Concept for reading and writing characters.
|
||||
|
||||
For read-only stream, no need to implement PutBegin(), Put() and PutEnd().
|
||||
|
||||
For write-only stream, only need to implement Put().
|
||||
|
||||
\code
|
||||
concept Stream {
|
||||
typename Ch; //!< Character type of the stream.
|
||||
|
||||
//! Read the current character from stream without moving the read cursor.
|
||||
Ch Peek() const;
|
||||
|
||||
//! Read the current character from stream and moving the read cursor to next character.
|
||||
Ch Take();
|
||||
|
||||
//! Get the current read cursor.
|
||||
//! \return Number of characters read from start.
|
||||
size_t Tell();
|
||||
|
||||
//! Begin writing operation at the current read pointer.
|
||||
//! \return The begin writer pointer.
|
||||
Ch* PutBegin();
|
||||
|
||||
//! Write a character.
|
||||
void Put(Ch c);
|
||||
|
||||
//! End the writing operation.
|
||||
//! \param begin The begin write pointer returned by PutBegin().
|
||||
//! \return Number of characters written.
|
||||
size_t PutEnd(Ch* begin);
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
|
||||
//! Put N copies of a character to a stream.
|
||||
template<typename Stream, typename Ch>
|
||||
inline void PutN(Stream& stream, Ch c, size_t n) {
|
||||
for (size_t i = 0; i < n; i++)
|
||||
stream.Put(c);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// StringStream
|
||||
|
||||
//! Read-only string stream.
|
||||
/*! \implements Stream
|
||||
*/
|
||||
template <typename Encoding>
|
||||
struct GenericStringStream {
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericStringStream(const Ch *src) : src_(src), head_(src) {}
|
||||
|
||||
Ch Peek() const { return *src_; }
|
||||
Ch Take() { return *src_++; }
|
||||
size_t Tell() const { return src_ - head_; }
|
||||
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
void Put(Ch c) { RAPIDJSON_ASSERT(false); }
|
||||
size_t PutEnd(Ch* begin) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
const Ch* src_; //!< Current read position.
|
||||
const Ch* head_; //!< Original head of the string.
|
||||
};
|
||||
|
||||
typedef GenericStringStream<UTF8<> > StringStream;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// InsituStringStream
|
||||
|
||||
//! A read-write string stream.
|
||||
/*! This string stream is particularly designed for in-situ parsing.
|
||||
\implements Stream
|
||||
*/
|
||||
template <typename Encoding>
|
||||
struct GenericInsituStringStream {
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {}
|
||||
|
||||
// Read
|
||||
Ch Peek() { return *src_; }
|
||||
Ch Take() { return *src_++; }
|
||||
size_t Tell() { return src_ - head_; }
|
||||
|
||||
// Write
|
||||
Ch* PutBegin() { return dst_ = src_; }
|
||||
void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }
|
||||
size_t PutEnd(Ch* begin) { return dst_ - begin; }
|
||||
|
||||
Ch* src_;
|
||||
Ch* dst_;
|
||||
Ch* head_;
|
||||
};
|
||||
|
||||
typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Type
|
||||
|
||||
//! Type of JSON value
|
||||
enum Type {
|
||||
kNullType = 0, //!< null
|
||||
kFalseType = 1, //!< false
|
||||
kTrueType = 2, //!< true
|
||||
kObjectType = 3, //!< object
|
||||
kArrayType = 4, //!< array
|
||||
kStringType = 5, //!< string
|
||||
kNumberType = 6, //!< number
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_RAPIDJSON_H_
|
664
include/rapidjson/reader.h
Normal file
664
include/rapidjson/reader.h
Normal file
@ -0,0 +1,664 @@
|
||||
#ifndef RAPIDJSON_READER_H_
|
||||
#define RAPIDJSON_READER_H_
|
||||
|
||||
// Copyright (c) 2011 Milo Yip (miloyip@gmail.com)
|
||||
// Version 0.1
|
||||
|
||||
#include "rapidjson.h"
|
||||
#include "internal/pow10.h"
|
||||
#include "internal/stack.h"
|
||||
#include <csetjmp>
|
||||
|
||||
#ifdef RAPIDJSON_SSE42
|
||||
#include <nmmintrin.h>
|
||||
#elif defined(RAPIDJSON_SSE2)
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
#ifndef RAPIDJSON_PARSE_ERROR
|
||||
#define RAPIDJSON_PARSE_ERROR(msg, offset) do { parseError_ = msg; errorOffset_ = offset; longjmp(jmpbuf_, 1); } while(false)
|
||||
#endif
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ParseFlag
|
||||
|
||||
//! Combination of parseFlags
|
||||
enum ParseFlag {
|
||||
kParseDefaultFlags = 0, //!< Default parse flags. Non-destructive parsing. Text strings are decoded into allocated buffer.
|
||||
kParseInsituFlag = 1 //!< In-situ(destructive) parsing.
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Handler
|
||||
|
||||
/*! \class rapidjson::Handler
|
||||
\brief Concept for receiving events from GenericReader upon parsing.
|
||||
\code
|
||||
concept Handler {
|
||||
typename Ch;
|
||||
|
||||
void Null();
|
||||
void Bool(bool b);
|
||||
void Int(int i);
|
||||
void Uint(unsigned i);
|
||||
void Int64(int64_t i);
|
||||
void Uint64(uint64_t i);
|
||||
void Double(double d);
|
||||
void String(const Ch* str, SizeType length, bool copy);
|
||||
void StartObject();
|
||||
void EndObject(SizeType memberCount);
|
||||
void StartArray();
|
||||
void EndArray(SizeType elementCount);
|
||||
};
|
||||
\endcode
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BaseReaderHandler
|
||||
|
||||
//! Default implementation of Handler.
|
||||
/*! This can be used as base class of any reader handler.
|
||||
\implements Handler
|
||||
*/
|
||||
template<typename Encoding = UTF8<> >
|
||||
struct BaseReaderHandler {
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
void Default() {}
|
||||
void Null() { Default(); }
|
||||
void Bool(bool b) { Default(); }
|
||||
void Int(int i) { Default(); }
|
||||
void Uint(unsigned i) { Default(); }
|
||||
void Int64(int64_t i) { Default(); }
|
||||
void Uint64(uint64_t i) { Default(); }
|
||||
void Double(double d) { Default(); }
|
||||
void String(const Ch* str, SizeType length, bool copy) { Default(); }
|
||||
void StartObject() { Default(); }
|
||||
void EndObject(SizeType memberCount) { Default(); }
|
||||
void StartArray() { Default(); }
|
||||
void EndArray(SizeType elementCount) { Default(); }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SkipWhitespace
|
||||
|
||||
//! Skip the JSON white spaces in a stream.
|
||||
/*! \param stream A input stream for skipping white spaces.
|
||||
\note This function has SSE2/SSE4.2 specialization.
|
||||
*/
|
||||
template<typename Stream>
|
||||
void SkipWhitespace(Stream& stream) {
|
||||
Stream s = stream; // Use a local copy for optimization
|
||||
while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t')
|
||||
s.Take();
|
||||
stream = s;
|
||||
}
|
||||
|
||||
#ifdef RAPIDJSON_SSE42
|
||||
//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.
|
||||
inline const char *SkipWhitespace_SIMD(const char* p) {
|
||||
static const char whitespace[16] = " \n\r\t";
|
||||
__m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]);
|
||||
|
||||
for (;;) {
|
||||
__m128i s = _mm_loadu_si128((const __m128i *)p);
|
||||
unsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
|
||||
if (r == 0) // all 16 characters are whitespace
|
||||
p += 16;
|
||||
else { // some of characters may be non-whitespace
|
||||
#ifdef _MSC_VER // Find the index of first non-whitespace
|
||||
unsigned long offset;
|
||||
if (_BitScanForward(&offset, r))
|
||||
return p + offset;
|
||||
#else
|
||||
if (r != 0)
|
||||
return p + __builtin_ffs(r) - 1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(RAPIDJSON_SSE2)
|
||||
|
||||
//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.
|
||||
inline const char *SkipWhitespace_SIMD(const char* p) {
|
||||
static const char whitespaces[4][17] = {
|
||||
" ",
|
||||
"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
||||
"\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r",
|
||||
"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"};
|
||||
|
||||
__m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]);
|
||||
__m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]);
|
||||
__m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]);
|
||||
__m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]);
|
||||
|
||||
for (;;) {
|
||||
__m128i s = _mm_loadu_si128((const __m128i *)p);
|
||||
__m128i x = _mm_cmpeq_epi8(s, w0);
|
||||
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
|
||||
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
|
||||
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
|
||||
unsigned short r = ~_mm_movemask_epi8(x);
|
||||
if (r == 0) // all 16 characters are whitespace
|
||||
p += 16;
|
||||
else { // some of characters may be non-whitespace
|
||||
#ifdef _MSC_VER // Find the index of first non-whitespace
|
||||
unsigned long offset;
|
||||
if (_BitScanForward(&offset, r))
|
||||
return p + offset;
|
||||
#else
|
||||
if (r != 0)
|
||||
return p + __builtin_ffs(r) - 1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // RAPIDJSON_SSE2
|
||||
|
||||
#ifdef RAPIDJSON_SIMD
|
||||
//! Template function specialization for InsituStringStream
|
||||
template<> inline void SkipWhitespace(InsituStringStream& stream) {
|
||||
stream.src_ = const_cast<char*>(SkipWhitespace_SIMD(stream.src_));
|
||||
}
|
||||
|
||||
//! Template function specialization for StringStream
|
||||
template<> inline void SkipWhitespace(StringStream& stream) {
|
||||
stream.src_ = SkipWhitespace_SIMD(stream.src_);
|
||||
}
|
||||
#endif // RAPIDJSON_SIMD
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GenericReader
|
||||
|
||||
//! SAX-style JSON parser. Use Reader for UTF8 encoding and default allocator.
|
||||
/*! GenericReader parses JSON text from a stream, and send events synchronously to an
|
||||
object implementing Handler concept.
|
||||
|
||||
It needs to allocate a stack for storing a single decoded string during
|
||||
non-destructive parsing.
|
||||
|
||||
For in-situ parsing, the decoded string is directly written to the source
|
||||
text string, no temporary buffer is required.
|
||||
|
||||
A GenericReader object can be reused for parsing multiple JSON text.
|
||||
|
||||
\tparam Encoding Encoding of both the stream and the parse output.
|
||||
\tparam Allocator Allocator type for stack.
|
||||
*/
|
||||
template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
|
||||
class GenericReader {
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
//! Constructor.
|
||||
/*! \param allocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
|
||||
\param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing)
|
||||
*/
|
||||
GenericReader(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseError_(0), errorOffset_(0) {}
|
||||
|
||||
//! Parse JSON text.
|
||||
/*! \tparam parseFlags Combination of ParseFlag.
|
||||
\tparam Stream Type of input stream.
|
||||
\tparam Handler Type of handler which must implement Handler concept.
|
||||
\param stream Input stream to be parsed.
|
||||
\param handler The handler to receive events.
|
||||
\return Whether the parsing is successful.
|
||||
*/
|
||||
template <unsigned parseFlags, typename Stream, typename Handler>
|
||||
bool Parse(Stream& stream, Handler& handler) {
|
||||
parseError_ = 0;
|
||||
errorOffset_ = 0;
|
||||
|
||||
if (setjmp(jmpbuf_)) {
|
||||
stack_.Clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
SkipWhitespace(stream);
|
||||
|
||||
if (stream.Peek() == '\0')
|
||||
RAPIDJSON_PARSE_ERROR("Text only contains white space(s)", stream.Tell());
|
||||
else {
|
||||
switch (stream.Peek()) {
|
||||
case '{': ParseObject<parseFlags>(stream, handler); break;
|
||||
case '[': ParseArray<parseFlags>(stream, handler); break;
|
||||
default: RAPIDJSON_PARSE_ERROR("Expect either an object or array at root", stream.Tell()); return false;
|
||||
}
|
||||
SkipWhitespace(stream);
|
||||
|
||||
if (stream.Peek() != '\0')
|
||||
RAPIDJSON_PARSE_ERROR("Nothing should follow the root object or array.", stream.Tell());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HasParseError() const { return parseError_ != 0; }
|
||||
const char* GetParseError() const { return parseError_; }
|
||||
size_t GetErrorOffset() const { return errorOffset_; }
|
||||
|
||||
private:
|
||||
// Parse object: { string : value, ... }
|
||||
template<unsigned parseFlags, typename Stream, typename Handler>
|
||||
void ParseObject(Stream& stream, Handler& handler) {
|
||||
RAPIDJSON_ASSERT(stream.Peek() == '{');
|
||||
stream.Take(); // Skip '{'
|
||||
handler.StartObject();
|
||||
SkipWhitespace(stream);
|
||||
|
||||
if (stream.Peek() == '}') {
|
||||
stream.Take();
|
||||
handler.EndObject(0); // empty object
|
||||
return;
|
||||
}
|
||||
|
||||
for (SizeType memberCount = 0;;) {
|
||||
if (stream.Peek() != '"') {
|
||||
RAPIDJSON_PARSE_ERROR("Name of an object member must be a string", stream.Tell());
|
||||
break;
|
||||
}
|
||||
|
||||
ParseString<parseFlags>(stream, handler);
|
||||
SkipWhitespace(stream);
|
||||
|
||||
if (stream.Take() != ':') {
|
||||
RAPIDJSON_PARSE_ERROR("There must be a colon after the name of object member", stream.Tell());
|
||||
break;
|
||||
}
|
||||
SkipWhitespace(stream);
|
||||
|
||||
ParseValue<parseFlags>(stream, handler);
|
||||
SkipWhitespace(stream);
|
||||
|
||||
++memberCount;
|
||||
|
||||
switch(stream.Take()) {
|
||||
case ',': SkipWhitespace(stream); break;
|
||||
case '}': handler.EndObject(memberCount); return;
|
||||
default: RAPIDJSON_PARSE_ERROR("Must be a comma or '}' after an object member", stream.Tell());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse array: [ value, ... ]
|
||||
template<unsigned parseFlags, typename Stream, typename Handler>
|
||||
void ParseArray(Stream& stream, Handler& handler) {
|
||||
RAPIDJSON_ASSERT(stream.Peek() == '[');
|
||||
stream.Take(); // Skip '['
|
||||
handler.StartArray();
|
||||
SkipWhitespace(stream);
|
||||
|
||||
if (stream.Peek() == ']') {
|
||||
stream.Take();
|
||||
handler.EndArray(0); // empty array
|
||||
return;
|
||||
}
|
||||
|
||||
for (SizeType elementCount = 0;;) {
|
||||
ParseValue<parseFlags>(stream, handler);
|
||||
++elementCount;
|
||||
SkipWhitespace(stream);
|
||||
|
||||
switch (stream.Take()) {
|
||||
case ',': SkipWhitespace(stream); break;
|
||||
case ']': handler.EndArray(elementCount); return;
|
||||
default: RAPIDJSON_PARSE_ERROR("Must be a comma or ']' after an array element.", stream.Tell());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned parseFlags, typename Stream, typename Handler>
|
||||
void ParseNull(Stream& stream, Handler& handler) {
|
||||
RAPIDJSON_ASSERT(stream.Peek() == 'n');
|
||||
stream.Take();
|
||||
|
||||
if (stream.Take() == 'u' && stream.Take() == 'l' && stream.Take() == 'l')
|
||||
handler.Null();
|
||||
else
|
||||
RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell() - 1);
|
||||
}
|
||||
|
||||
template<unsigned parseFlags, typename Stream, typename Handler>
|
||||
void ParseTrue(Stream& stream, Handler& handler) {
|
||||
RAPIDJSON_ASSERT(stream.Peek() == 't');
|
||||
stream.Take();
|
||||
|
||||
if (stream.Take() == 'r' && stream.Take() == 'u' && stream.Take() == 'e')
|
||||
handler.Bool(true);
|
||||
else
|
||||
RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell());
|
||||
}
|
||||
|
||||
template<unsigned parseFlags, typename Stream, typename Handler>
|
||||
void ParseFalse(Stream& stream, Handler& handler) {
|
||||
RAPIDJSON_ASSERT(stream.Peek() == 'f');
|
||||
stream.Take();
|
||||
|
||||
if (stream.Take() == 'a' && stream.Take() == 'l' && stream.Take() == 's' && stream.Take() == 'e')
|
||||
handler.Bool(false);
|
||||
else
|
||||
RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell() - 1);
|
||||
}
|
||||
|
||||
// Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
|
||||
template<typename Stream>
|
||||
unsigned ParseHex4(Stream& stream) {
|
||||
Stream s = stream; // Use a local copy for optimization
|
||||
unsigned codepoint = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Ch c = s.Take();
|
||||
codepoint <<= 4;
|
||||
codepoint += c;
|
||||
if (c >= '0' && c <= '9')
|
||||
codepoint -= '0';
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
codepoint -= 'A' - 10;
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
codepoint -= 'a' - 10;
|
||||
else {
|
||||
RAPIDJSON_PARSE_ERROR("Incorrect hex digit after \\u escape", s.Tell() - 1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
stream = s; // Restore stream
|
||||
return codepoint;
|
||||
}
|
||||
|
||||
// Parse string, handling the prefix and suffix double quotes and escaping.
|
||||
template<unsigned parseFlags, typename Stream, typename Handler>
|
||||
void ParseString(Stream& stream, Handler& handler) {
|
||||
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
static const Ch escape[256] = {
|
||||
Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/',
|
||||
Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
|
||||
0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0,
|
||||
0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
|
||||
};
|
||||
#undef Z16
|
||||
|
||||
Stream s = stream; // Use a local copy for optimization
|
||||
RAPIDJSON_ASSERT(s.Peek() == '\"');
|
||||
s.Take(); // Skip '\"'
|
||||
Ch *head;
|
||||
SizeType len;
|
||||
if (parseFlags & kParseInsituFlag)
|
||||
head = s.PutBegin();
|
||||
else
|
||||
len = 0;
|
||||
|
||||
#define RAPIDJSON_PUT(x) \
|
||||
do { \
|
||||
if (parseFlags & kParseInsituFlag) \
|
||||
s.Put(x); \
|
||||
else { \
|
||||
*stack_.template Push<Ch>() = x; \
|
||||
++len; \
|
||||
} \
|
||||
} while(false)
|
||||
|
||||
for (;;) {
|
||||
Ch c = s.Take();
|
||||
if (c == '\\') { // Escape
|
||||
Ch e = s.Take();
|
||||
if ((sizeof(Ch) == 1 || e < 256) && escape[(unsigned char)e])
|
||||
RAPIDJSON_PUT(escape[(unsigned char)e]);
|
||||
else if (e == 'u') { // Unicode
|
||||
unsigned codepoint = ParseHex4(s);
|
||||
if (codepoint >= 0xD800 && codepoint <= 0xDBFF) { // Handle UTF-16 surrogate pair
|
||||
if (s.Take() != '\\' || s.Take() != 'u') {
|
||||
RAPIDJSON_PARSE_ERROR("Missing the second \\u in surrogate pair", s.Tell() - 2);
|
||||
return;
|
||||
}
|
||||
unsigned codepoint2 = ParseHex4(s);
|
||||
if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF) {
|
||||
RAPIDJSON_PARSE_ERROR("The second \\u in surrogate pair is invalid", s.Tell() - 2);
|
||||
return;
|
||||
}
|
||||
codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
|
||||
}
|
||||
|
||||
Ch buffer[4];
|
||||
SizeType count = SizeType(Encoding::Encode(buffer, codepoint) - &buffer[0]);
|
||||
|
||||
if (parseFlags & kParseInsituFlag)
|
||||
for (SizeType i = 0; i < count; i++)
|
||||
s.Put(buffer[i]);
|
||||
else {
|
||||
memcpy(stack_.template Push<Ch>(count), buffer, count * sizeof(Ch));
|
||||
len += count;
|
||||
}
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_PARSE_ERROR("Unknown escape character", stream.Tell() - 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (c == '"') { // Closing double quote
|
||||
if (parseFlags & kParseInsituFlag) {
|
||||
size_t length = s.PutEnd(head);
|
||||
RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
|
||||
RAPIDJSON_PUT('\0'); // null-terminate the string
|
||||
handler.String(head, SizeType(length), false);
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_PUT('\0');
|
||||
handler.String(stack_.template Pop<Ch>(len), len - 1, true);
|
||||
}
|
||||
stream = s; // restore stream
|
||||
return;
|
||||
}
|
||||
else if (c == '\0') {
|
||||
RAPIDJSON_PARSE_ERROR("lacks ending quotation before the end of string", stream.Tell() - 1);
|
||||
return;
|
||||
}
|
||||
else if ((unsigned)c < 0x20) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
|
||||
RAPIDJSON_PARSE_ERROR("Incorrect unescaped character in string", stream.Tell() - 1);
|
||||
return;
|
||||
}
|
||||
else
|
||||
RAPIDJSON_PUT(c); // Normal character, just copy
|
||||
}
|
||||
#undef RAPIDJSON_PUT
|
||||
}
|
||||
|
||||
template<unsigned parseFlags, typename Stream, typename Handler>
|
||||
void ParseNumber(Stream& stream, Handler& handler) {
|
||||
Stream s = stream; // Local copy for optimization
|
||||
// Parse minus
|
||||
bool minus = false;
|
||||
if (s.Peek() == '-') {
|
||||
minus = true;
|
||||
s.Take();
|
||||
}
|
||||
|
||||
// Parse int: zero / ( digit1-9 *DIGIT )
|
||||
unsigned i;
|
||||
bool try64bit = false;
|
||||
if (s.Peek() == '0') {
|
||||
i = 0;
|
||||
s.Take();
|
||||
}
|
||||
else if (s.Peek() >= '1' && s.Peek() <= '9') {
|
||||
i = s.Take() - '0';
|
||||
|
||||
if (minus)
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
if (i >= 214748364) { // 2^31 = 2147483648
|
||||
if (i != 214748364 || s.Peek() > '8') {
|
||||
try64bit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
i = i * 10 + (s.Take() - '0');
|
||||
}
|
||||
else
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
if (i >= 429496729) { // 2^32 - 1 = 4294967295
|
||||
if (i != 429496729 || s.Peek() > '5') {
|
||||
try64bit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
i = i * 10 + (s.Take() - '0');
|
||||
}
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_PARSE_ERROR("Expect a value here.", stream.Tell());
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse 64bit int
|
||||
uint64_t i64;
|
||||
bool useDouble = false;
|
||||
if (try64bit) {
|
||||
i64 = i;
|
||||
if (minus)
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
if (i64 >= 922337203685477580uLL) // 2^63 = 9223372036854775808
|
||||
if (i64 != 922337203685477580uLL || s.Peek() > '8') {
|
||||
useDouble = true;
|
||||
break;
|
||||
}
|
||||
i64 = i64 * 10 + (s.Take() - '0');
|
||||
}
|
||||
else
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
if (i64 >= 1844674407370955161uLL) // 2^64 - 1 = 18446744073709551615
|
||||
if (i64 != 1844674407370955161uLL || s.Peek() > '5') {
|
||||
useDouble = true;
|
||||
break;
|
||||
}
|
||||
i64 = i64 * 10 + (s.Take() - '0');
|
||||
}
|
||||
}
|
||||
|
||||
// Force double for big integer
|
||||
double d;
|
||||
if (useDouble) {
|
||||
d = (double)i64;
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
if (d >= 1E307) {
|
||||
RAPIDJSON_PARSE_ERROR("Number too big to store in double", stream.Tell());
|
||||
return;
|
||||
}
|
||||
d = d * 10 + (s.Take() - '0');
|
||||
}
|
||||
}
|
||||
|
||||
// Parse frac = decimal-point 1*DIGIT
|
||||
int expFrac = 0;
|
||||
if (s.Peek() == '.') {
|
||||
if (!useDouble) {
|
||||
d = try64bit ? (double)i64 : (double)i;
|
||||
useDouble = true;
|
||||
}
|
||||
s.Take();
|
||||
|
||||
if (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
d = d * 10 + (s.Take() - '0');
|
||||
--expFrac;
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_PARSE_ERROR("At least one digit in fraction part", stream.Tell());
|
||||
return;
|
||||
}
|
||||
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
if (expFrac > -16) {
|
||||
d = d * 10 + (s.Peek() - '0');
|
||||
--expFrac;
|
||||
}
|
||||
s.Take();
|
||||
}
|
||||
}
|
||||
|
||||
// Parse exp = e [ minus / plus ] 1*DIGIT
|
||||
int exp = 0;
|
||||
if (s.Peek() == 'e' || s.Peek() == 'E') {
|
||||
if (!useDouble) {
|
||||
d = try64bit ? (double)i64 : (double)i;
|
||||
useDouble = true;
|
||||
}
|
||||
s.Take();
|
||||
|
||||
bool expMinus = false;
|
||||
if (s.Peek() == '+')
|
||||
s.Take();
|
||||
else if (s.Peek() == '-') {
|
||||
s.Take();
|
||||
expMinus = true;
|
||||
}
|
||||
|
||||
if (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
exp = s.Take() - '0';
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
exp = exp * 10 + (s.Take() - '0');
|
||||
if (exp > 308) {
|
||||
RAPIDJSON_PARSE_ERROR("Number too big to store in double", stream.Tell());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_PARSE_ERROR("At least one digit in exponent", s.Tell());
|
||||
return;
|
||||
}
|
||||
|
||||
if (expMinus)
|
||||
exp = -exp;
|
||||
}
|
||||
|
||||
// Finish parsing, call event according to the type of number.
|
||||
if (useDouble) {
|
||||
d *= internal::Pow10(exp + expFrac);
|
||||
handler.Double(minus ? -d : d);
|
||||
}
|
||||
else {
|
||||
if (try64bit) {
|
||||
if (minus)
|
||||
handler.Int64(-(int64_t)i64);
|
||||
else
|
||||
handler.Uint64(i64);
|
||||
}
|
||||
else {
|
||||
if (minus)
|
||||
handler.Int(-(int)i);
|
||||
else
|
||||
handler.Uint(i);
|
||||
}
|
||||
}
|
||||
|
||||
stream = s; // restore stream
|
||||
}
|
||||
|
||||
// Parse any JSON value
|
||||
template<unsigned parseFlags, typename Stream, typename Handler>
|
||||
void ParseValue(Stream& stream, Handler& handler) {
|
||||
switch (stream.Peek()) {
|
||||
case 'n': ParseNull <parseFlags>(stream, handler); break;
|
||||
case 't': ParseTrue <parseFlags>(stream, handler); break;
|
||||
case 'f': ParseFalse <parseFlags>(stream, handler); break;
|
||||
case '"': ParseString<parseFlags>(stream, handler); break;
|
||||
case '{': ParseObject<parseFlags>(stream, handler); break;
|
||||
case '[': ParseArray <parseFlags>(stream, handler); break;
|
||||
default : ParseNumber<parseFlags>(stream, handler);
|
||||
}
|
||||
}
|
||||
|
||||
static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string.
|
||||
internal::Stack<Allocator> stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing.
|
||||
jmp_buf jmpbuf_; //!< setjmp buffer for fast exit from nested parsing function calls.
|
||||
const char* parseError_;
|
||||
size_t errorOffset_;
|
||||
}; // class GenericReader
|
||||
|
||||
//! Reader with UTF8 encoding and default allocator.
|
||||
typedef GenericReader<UTF8<> > Reader;
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_READER_H_
|
49
include/rapidjson/stringbuffer.h
Normal file
49
include/rapidjson/stringbuffer.h
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef RAPIDJSON_STRINGBUFFER_H_
|
||||
#define RAPIDJSON_STRINGBUFFER_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
#include "internal/stack.h"
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! Represents an in-memory output stream.
|
||||
/*!
|
||||
\tparam Encoding Encoding of the stream.
|
||||
\tparam Allocator type for allocating memory buffer.
|
||||
\implements Stream
|
||||
*/
|
||||
template <typename Encoding, typename Allocator = CrtAllocator>
|
||||
struct GenericStringBuffer {
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
|
||||
|
||||
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
|
||||
|
||||
void Clear() { stack_.Clear(); }
|
||||
|
||||
const char* GetString() const {
|
||||
// Push and pop a null terminator. This is safe.
|
||||
*stack_.template Push<Ch>() = '\0';
|
||||
stack_.template Pop<Ch>(1);
|
||||
|
||||
return stack_.template Bottom<Ch>();
|
||||
}
|
||||
|
||||
size_t Size() const { return stack_.Size(); }
|
||||
|
||||
static const size_t kDefaultCapacity = 256;
|
||||
mutable internal::Stack<Allocator> stack_;
|
||||
};
|
||||
|
||||
typedef GenericStringBuffer<UTF8<> > StringBuffer;
|
||||
|
||||
//! Implement specialized version of PutN() with memset() for better performance.
|
||||
template<>
|
||||
inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
|
||||
memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
|
||||
}
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_STRINGBUFFER_H_
|
224
include/rapidjson/writer.h
Normal file
224
include/rapidjson/writer.h
Normal file
@ -0,0 +1,224 @@
|
||||
#ifndef RAPIDJSON_WRITER_H_
|
||||
#define RAPIDJSON_WRITER_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
#include "internal/stack.h"
|
||||
#include "internal/strfunc.h"
|
||||
#include <cstdio> // snprintf() or _sprintf_s()
|
||||
#include <new> // placement new
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! JSON writer
|
||||
/*! Writer implements the concept Handler.
|
||||
It generates JSON text by events to an output stream.
|
||||
|
||||
User may programmatically calls the functions of a writer to generate JSON text.
|
||||
|
||||
On the other side, a writer can also be passed to objects that generates events,
|
||||
|
||||
for example Reader::Parse() and Document::Accept().
|
||||
|
||||
\tparam Stream Type of ouptut stream.
|
||||
\tparam Encoding Encoding of both source strings and output.
|
||||
\implements Handler
|
||||
*/
|
||||
template<typename Stream, typename Encoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
|
||||
class Writer {
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
Writer(Stream& stream, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
|
||||
stream_(stream), level_stack_(allocator, levelDepth * sizeof(Level)) {}
|
||||
|
||||
//@name Implementation of Handler
|
||||
//@{
|
||||
Writer& Null() { Prefix(kNullType); WriteNull(); return *this; }
|
||||
Writer& Bool(bool b) { Prefix(b ? kTrueType : kFalseType); WriteBool(b); return *this; }
|
||||
Writer& Int(int i) { Prefix(kNumberType); WriteInt(i); return *this; }
|
||||
Writer& Uint(unsigned u) { Prefix(kNumberType); WriteUint(u); return *this; }
|
||||
Writer& Int64(int64_t i64) { Prefix(kNumberType); WriteInt64(i64); return *this; }
|
||||
Writer& Uint64(uint64_t u64) { Prefix(kNumberType); WriteUint64(u64); return *this; }
|
||||
Writer& Double(double d) { Prefix(kNumberType); WriteDouble(d); return *this; }
|
||||
|
||||
Writer& String(const Ch* str, SizeType length, bool copy = false) {
|
||||
Prefix(kStringType);
|
||||
WriteString(str, length);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Writer& StartObject() {
|
||||
Prefix(kObjectType);
|
||||
new (level_stack_.template Push<Level>()) Level(false);
|
||||
WriteStartObject();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Writer& EndObject(SizeType memberCount = 0) {
|
||||
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
|
||||
RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
|
||||
level_stack_.template Pop<Level>(1);
|
||||
WriteEndObject();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Writer& StartArray() {
|
||||
Prefix(kArrayType);
|
||||
new (level_stack_.template Push<Level>()) Level(true);
|
||||
WriteStartArray();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Writer& EndArray(SizeType elementCount = 0) {
|
||||
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
|
||||
RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
|
||||
level_stack_.template Pop<Level>(1);
|
||||
WriteEndArray();
|
||||
return *this;
|
||||
}
|
||||
//@}
|
||||
|
||||
//! Simpler but slower overload.
|
||||
Writer& String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
||||
|
||||
protected:
|
||||
//! Information for each nested level
|
||||
struct Level {
|
||||
Level(bool inArray) : inArray(inArray), valueCount(0) {}
|
||||
bool inArray; //!< true if in array, otherwise in object
|
||||
size_t valueCount; //!< number of values in this level
|
||||
};
|
||||
|
||||
static const size_t kDefaultLevelDepth = 32;
|
||||
|
||||
void WriteNull() {
|
||||
stream_.Put('n'); stream_.Put('u'); stream_.Put('l'); stream_.Put('l');
|
||||
}
|
||||
|
||||
void WriteBool(bool b) {
|
||||
if (b) {
|
||||
stream_.Put('t'); stream_.Put('r'); stream_.Put('u'); stream_.Put('e');
|
||||
}
|
||||
else {
|
||||
stream_.Put('f'); stream_.Put('a'); stream_.Put('l'); stream_.Put('s'); stream_.Put('e');
|
||||
}
|
||||
}
|
||||
|
||||
void WriteInt(int i) {
|
||||
if (i < 0) {
|
||||
stream_.Put('-');
|
||||
i = -i;
|
||||
}
|
||||
WriteUint((unsigned)i);
|
||||
}
|
||||
|
||||
void WriteUint(unsigned u) {
|
||||
char buffer[10];
|
||||
char *p = buffer;
|
||||
do {
|
||||
*p++ = (u % 10) + '0';
|
||||
u /= 10;
|
||||
} while (u > 0);
|
||||
|
||||
do {
|
||||
--p;
|
||||
stream_.Put(*p);
|
||||
} while (p != buffer);
|
||||
}
|
||||
|
||||
void WriteInt64(int64_t i64) {
|
||||
if (i64 < 0) {
|
||||
stream_.Put('-');
|
||||
i64 = -i64;
|
||||
}
|
||||
WriteUint64((uint64_t)i64);
|
||||
}
|
||||
|
||||
void WriteUint64(uint64_t u64) {
|
||||
char buffer[20];
|
||||
char *p = buffer;
|
||||
do {
|
||||
*p++ = char(u64 % 10) + '0';
|
||||
u64 /= 10;
|
||||
} while (u64 > 0);
|
||||
|
||||
do {
|
||||
--p;
|
||||
stream_.Put(*p);
|
||||
} while (p != buffer);
|
||||
}
|
||||
|
||||
//! \todo Optimization with custom double-to-string converter.
|
||||
void WriteDouble(double d) {
|
||||
char buffer[100];
|
||||
#if _MSC_VER
|
||||
int ret = sprintf_s(buffer, sizeof(buffer), "%g", d);
|
||||
#else
|
||||
int ret = snprintf(buffer, sizeof(buffer), "%g", d);
|
||||
#endif
|
||||
RAPIDJSON_ASSERT(ret >= 1);
|
||||
for (int i = 0; i < ret; i++)
|
||||
stream_.Put(buffer[i]);
|
||||
}
|
||||
|
||||
void WriteString(const Ch* str, SizeType length) {
|
||||
static const char hexDigits[] = "0123456789ABCDEF";
|
||||
static const char escape[256] = {
|
||||
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
//0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
|
||||
0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
|
||||
Z16, Z16, // 30~4F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
|
||||
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
|
||||
#undef Z16
|
||||
};
|
||||
|
||||
stream_.Put('\"');
|
||||
for (const Ch* p = str; p != str + length; ++p) {
|
||||
if ((sizeof(Ch) == 1 || *p < 256) && escape[(unsigned char)*p]) {
|
||||
stream_.Put('\\');
|
||||
stream_.Put(escape[(unsigned char)*p]);
|
||||
if (escape[(unsigned char)*p] == 'u') {
|
||||
stream_.Put('0');
|
||||
stream_.Put('0');
|
||||
stream_.Put(hexDigits[(*p) >> 4]);
|
||||
stream_.Put(hexDigits[(*p) & 0xF]);
|
||||
}
|
||||
}
|
||||
else
|
||||
stream_.Put(*p);
|
||||
}
|
||||
stream_.Put('\"');
|
||||
}
|
||||
|
||||
void WriteStartObject() { stream_.Put('{'); }
|
||||
void WriteEndObject() { stream_.Put('}'); }
|
||||
void WriteStartArray() { stream_.Put('['); }
|
||||
void WriteEndArray() { stream_.Put(']'); }
|
||||
|
||||
void Prefix(Type type) {
|
||||
if (level_stack_.GetSize() != 0) { // this value is not at root
|
||||
Level* level = level_stack_.template Top<Level>();
|
||||
if (level->valueCount > 0) {
|
||||
if (level->inArray)
|
||||
stream_.Put(','); // add comma if it is not the first element in array
|
||||
else // in object
|
||||
stream_.Put((level->valueCount % 2 == 0) ? ',' : ':');
|
||||
}
|
||||
if (!level->inArray && level->valueCount % 2 == 0)
|
||||
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
|
||||
level->valueCount++;
|
||||
}
|
||||
else
|
||||
RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
|
||||
}
|
||||
|
||||
Stream& stream_;
|
||||
internal::Stack<Allocator> level_stack_;
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_RAPIDJSON_H_
|
19
license.txt
Normal file
19
license.txt
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (C) 2011 Milo Yip
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
34
readme.txt
Normal file
34
readme.txt
Normal file
@ -0,0 +1,34 @@
|
||||
Rapidjson v0.1
|
||||
|
||||
Copyright (c) 2011 Milo Yip (miloyip@gmail.com)
|
||||
|
||||
http://code.google.com/p/rapidjson/
|
||||
|
||||
19 Nov 2011
|
||||
|
||||
1. Introduction
|
||||
Rapidjson is a JSON parser and generator for C++. It was inspired by rapidxml http://rapidxml.sourceforge.net/
|
||||
Rapidjson is small but complete. It supports both SAX and DOM style API. The SAX parser is only a half thousand lines of code.
|
||||
Rapidjson is fast. Its performance can be comparable to strlen(). It also optionally supports SSE2/SSE4.1 for acceleration.
|
||||
Rapidjson is self-contained. It does not depend on external libraries such as BOOST. It even does not depend on STL.
|
||||
Rapidjson is memory friendly. Each JSON value costs exactly 16/20 bytes for 32/64-bit machines (excluding text string). By default it uses a fast memory allocator, and the parser allocates memory compactly during parsing.
|
||||
|
||||
For the full features please refer to the user guide.
|
||||
|
||||
JSON(JavaScript Object Notation) is a light-weight data exchange format.
|
||||
More information about JSON can be obtained at
|
||||
http://json.org/
|
||||
http://www.ietf.org/rfc/rfc4627.txt
|
||||
|
||||
2. Installation
|
||||
|
||||
Rapidjson is a header-only C++ library. Just copy the rapidjson/include/rapidjson folder to system or project's include path.
|
||||
|
||||
To build the tests and examples,
|
||||
1. obtain premake4 http://industriousone.com/premake/download
|
||||
2. Copy premake4 executable to rapidjson/build
|
||||
3. Run rapidjson/build/premake.bat on Windows, rapidjson/build/premake on Linux or other platforms
|
||||
4. On Windows, build the solution at rapidjson/build/vs2008/ or /vs2010/
|
||||
5. On other platforms, run GNU make at rapidjson/build/gmake/ (e.g., make -f test.make config=release32, make -f example.make config=debug32)
|
||||
6. On success, the executable are generated at rapidjson/bin
|
||||
|
57
test/perftest/jsoncpptest.cpp
Normal file
57
test/perftest/jsoncpptest.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
#include "perftest.h"
|
||||
|
||||
#if TEST_JSONCPP
|
||||
|
||||
#include "jsoncpp/src/lib_json/json_reader.cpp"
|
||||
#include "jsoncpp/src/lib_json/json_value.cpp"
|
||||
#include "jsoncpp/src/lib_json/json_writer.cpp"
|
||||
|
||||
using namespace Json;
|
||||
|
||||
class JsonCpp : public PerfTest {
|
||||
public:
|
||||
virtual void SetUp() {
|
||||
PerfTest::SetUp();
|
||||
Reader reader;
|
||||
ASSERT_TRUE(reader.parse(json_, root_));
|
||||
}
|
||||
|
||||
protected:
|
||||
Value root_;
|
||||
};
|
||||
|
||||
TEST_F(JsonCpp, ReaderParse) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
Value root;
|
||||
Reader reader;
|
||||
ASSERT_TRUE(reader.parse(json_, root));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(JsonCpp, FastWriter) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
FastWriter writer;
|
||||
std::string str = writer.write(root_);
|
||||
//if (i == 0)
|
||||
// std::cout << str.length() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(JsonCpp, StyledWriter) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
StyledWriter writer;
|
||||
std::string str = writer.write(root_);
|
||||
//if (i == 0)
|
||||
// std::cout << str.length() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(JsonCpp, Whitespace) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
Value root;
|
||||
Reader reader;
|
||||
ASSERT_TRUE(reader.parse(whitespace_, root));
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TEST_JSONCPP
|
10
test/perftest/perftest.cpp
Normal file
10
test/perftest/perftest.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
#include "perftest.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
#if _MSC_VER
|
||||
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
|
||||
//void *testWhetherMemoryLeakDetectionWorks = malloc(1);
|
||||
#endif
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
82
test/perftest/perftest.h
Normal file
82
test/perftest/perftest.h
Normal file
@ -0,0 +1,82 @@
|
||||
#ifndef PERFTEST_H_
|
||||
#define PERFTEST_H_
|
||||
|
||||
#define TEST_RAPIDJSON 1
|
||||
#define TEST_JSONCPP 1
|
||||
#define TEST_YAJL 1
|
||||
|
||||
#if TEST_RAPIDJSON
|
||||
//#define RAPIDJSON_SSE2
|
||||
//#define RAPIDJSON_SSE42
|
||||
#endif
|
||||
|
||||
#if TEST_YAJL
|
||||
#include "yajl/yajl_common.h"
|
||||
#undef YAJL_MAX_DEPTH
|
||||
#define YAJL_MAX_DEPTH 1024
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Google Test
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
#include <crtdbg.h>
|
||||
#pragma warning(disable : 4996) // 'function': was declared deprecated
|
||||
#endif
|
||||
|
||||
//! Base class for all performance tests
|
||||
class PerfTest : public ::testing::Test {
|
||||
public:
|
||||
virtual void SetUp() {
|
||||
FILE *fp = fopen("data/sample.json", "rb");
|
||||
if (!fp)
|
||||
fp = fopen("../../bin/data/sample.json", "rb");
|
||||
ASSERT_TRUE(fp != 0);
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
length_ = (size_t)ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
json_ = (char*)malloc(length_ + 1);
|
||||
fread(json_, 1, length_, fp);
|
||||
json_[length_] = '\0';
|
||||
length_++; // include the null terminator
|
||||
fclose(fp);
|
||||
|
||||
// whitespace test
|
||||
whitespace_length_ = 1024 * 1024;
|
||||
whitespace_ = (char *)malloc(whitespace_length_ + 4);
|
||||
char *p = whitespace_;
|
||||
for (size_t i = 0; i < whitespace_length_; i += 4) {
|
||||
*p++ = ' ';
|
||||
*p++ = '\n';
|
||||
*p++ = '\r';
|
||||
*p++ = '\t';
|
||||
}
|
||||
*p++ = '[';
|
||||
*p++ = '0';
|
||||
*p++ = ']';
|
||||
*p++ = '\0';
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
free(json_);
|
||||
free(whitespace_);
|
||||
}
|
||||
|
||||
protected:
|
||||
char *json_;
|
||||
size_t length_;
|
||||
char *whitespace_;
|
||||
size_t whitespace_length_;
|
||||
|
||||
static const size_t kTrialCount = 1000;
|
||||
};
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // PERFTEST_H_
|
234
test/perftest/rapidjsontest.cpp
Normal file
234
test/perftest/rapidjsontest.cpp
Normal file
@ -0,0 +1,234 @@
|
||||
#include "perftest.h"
|
||||
|
||||
#if TEST_RAPIDJSON
|
||||
|
||||
#include "rapidjson/rapidjson.h"
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/prettywriter.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include "rapidjson/filestream.h"
|
||||
#include <cmath>
|
||||
|
||||
#ifdef RAPIDJSON_SSE2
|
||||
#define SIMD_SUFFIX(name) name##_SSE2
|
||||
#elif defined(RAPIDJSON_SSE42)
|
||||
#define SIMD_SUFFIX(name) name##_SSE42
|
||||
#else
|
||||
#define SIMD_SUFFIX(name) name
|
||||
#endif
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
class RapidJson : public PerfTest {
|
||||
public:
|
||||
virtual void SetUp() {
|
||||
PerfTest::SetUp();
|
||||
|
||||
// temp buffer for insitu parsing.
|
||||
temp_ = (char *)malloc(length_ + 1);
|
||||
|
||||
// Parse as a document
|
||||
EXPECT_FALSE(doc_.Parse<0>(json_).IsNull());
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
PerfTest::TearDown();
|
||||
free(temp_);
|
||||
}
|
||||
|
||||
protected:
|
||||
char *temp_;
|
||||
Document doc_;
|
||||
};
|
||||
|
||||
TEST_F(RapidJson, strlen) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
size_t l = strlen(json_);
|
||||
EXPECT_EQ(length_, l + 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseInsitu_NullHandler)) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
memcpy(temp_, json_, length_);
|
||||
InsituStringStream s(temp_);
|
||||
BaseReaderHandler<> h;
|
||||
Reader reader;
|
||||
reader.Parse<kParseInsituFlag>(s, h);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(DoucmentParseInsitu_MemoryPoolAllocator)) {
|
||||
//const size_t userBufferSize = 128 * 1024;
|
||||
//char* userBuffer = (char*)malloc(userBufferSize);
|
||||
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
memcpy(temp_, json_, length_);
|
||||
//MemoryPoolAllocator<> allocator(userBuffer, userBufferSize);
|
||||
//Document doc(&allocator);
|
||||
Document doc;
|
||||
doc.ParseInsitu<0>(temp_);
|
||||
ASSERT_TRUE(doc.IsObject());
|
||||
//if (i == 0) {
|
||||
// size_t size = doc.GetAllocator().Size();
|
||||
// size_t capacity = doc.GetAllocator().Capacity();
|
||||
// size_t stack_capacity = doc.GetStackCapacity();
|
||||
// size_t actual = size - stack_capacity;
|
||||
// std::cout << "Size:" << size << " Capacity:" << capacity << " Stack:" << stack_capacity << " Actual:" << actual << std::endl;
|
||||
//}
|
||||
}
|
||||
|
||||
//free(userBuffer);
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(DoucmentParse_MemoryPoolAllocator)) {
|
||||
//const size_t userBufferSize = 128 * 1024;
|
||||
//char* userBuffer = (char*)malloc(userBufferSize);
|
||||
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
//MemoryPoolAllocator<> allocator(userBuffer, userBufferSize);
|
||||
//Document doc(&allocator);
|
||||
Document doc;
|
||||
doc.Parse<0>(json_);
|
||||
ASSERT_TRUE(doc.IsObject());
|
||||
//if (i == 0) {
|
||||
// size_t size = doc.GetAllocator().Size();
|
||||
// size_t capacity = doc.GetAllocator().Capacity();
|
||||
// size_t stack_capacity = doc.GetStackCapacity();
|
||||
// size_t actual = size - stack_capacity;
|
||||
// std::cout << "Size:" << size << " Capacity:" << capacity << " Stack:" << stack_capacity << " Actual:" << actual << std::endl;
|
||||
//}
|
||||
}
|
||||
|
||||
//free(userBuffer);
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(DoucmentParse_CrtAllocator)) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
memcpy(temp_, json_, length_);
|
||||
GenericDocument<UTF8<>, CrtAllocator> doc;
|
||||
doc.Parse<0>(temp_);
|
||||
ASSERT_TRUE(doc.IsObject());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
size_t Traverse(const T& value) {
|
||||
size_t count = 1;
|
||||
switch(value.GetType()) {
|
||||
case kObjectType:
|
||||
for (typename T::ConstMemberIterator itr = value.MemberBegin(); itr != value.MemberEnd(); ++itr) {
|
||||
count++; // name
|
||||
count += Traverse(itr->value);
|
||||
}
|
||||
break;
|
||||
|
||||
case kArrayType:
|
||||
for (typename T::ConstValueIterator itr = value.Begin(); itr != value.End(); ++itr)
|
||||
count += Traverse(*itr);
|
||||
break;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, DocumentTraverse) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
size_t count = Traverse(doc_);
|
||||
EXPECT_EQ(4339, count);
|
||||
//if (i == 0)
|
||||
// std::cout << count << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
struct ValueCounter : public BaseReaderHandler<> {
|
||||
ValueCounter() : count_(1) {} // root
|
||||
|
||||
void EndObject(SizeType memberCount) { count_ += memberCount * 2; }
|
||||
void EndArray(SizeType elementCount) { count_ += elementCount; }
|
||||
|
||||
SizeType count_;
|
||||
};
|
||||
|
||||
TEST_F(RapidJson, DocumentAccept) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
ValueCounter counter;
|
||||
doc_.Accept(counter);
|
||||
EXPECT_EQ(4339, counter.count_);
|
||||
}
|
||||
}
|
||||
|
||||
struct NullStream {
|
||||
NullStream() : length_(0) {}
|
||||
void Put(char c) { ++length_; }
|
||||
size_t length_;
|
||||
};
|
||||
|
||||
TEST_F(RapidJson, Writer_NullStream) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
NullStream s;
|
||||
Writer<NullStream> writer(s);
|
||||
doc_.Accept(writer);
|
||||
//if (i == 0)
|
||||
// std::cout << s.length_ << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, Writer_StringBuffer) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
StringBuffer s(0, 1024 * 1024);
|
||||
Writer<StringBuffer> writer(s);
|
||||
doc_.Accept(writer);
|
||||
const char* str = s.GetString();
|
||||
//if (i == 0)
|
||||
// std::cout << strlen(str) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, PrettyWriter_StringBuffer) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
StringBuffer s(0, 2048 * 1024);
|
||||
PrettyWriter<StringBuffer> writer(s);
|
||||
writer.SetIndent(' ', 1);
|
||||
doc_.Accept(writer);
|
||||
const char* str = s.GetString();
|
||||
//if (i == 0)
|
||||
// std::cout << strlen(str) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, pow) {
|
||||
double sum = 0;
|
||||
for (int i = 0; i < kTrialCount * kTrialCount; i++)
|
||||
sum += pow(10.0, i & 255);
|
||||
EXPECT_GT(sum, 0.0);
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, internal_Pow10) {
|
||||
double sum = 0;
|
||||
for (int i = 0; i < kTrialCount * kTrialCount; i++)
|
||||
sum += internal::Pow10(i & 255);
|
||||
EXPECT_GT(sum, 0.0);
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, Whitespace_strlen) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
size_t l = strlen(whitespace_);
|
||||
EXPECT_GT(l, whitespace_length_);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, Whitespace_strspn) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
size_t l = strspn(whitespace_, " \n\r\t");
|
||||
EXPECT_EQ(whitespace_length_, l);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(Whitespace)) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
Document doc;
|
||||
ASSERT_TRUE(doc.Parse<0>(whitespace_).IsArray());
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TEST_RAPIDJSON
|
22
test/perftest/yajl_all.c
Normal file
22
test/perftest/yajl_all.c
Normal file
@ -0,0 +1,22 @@
|
||||
#include "perftest.h"
|
||||
|
||||
#if TEST_YAJL
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <float.h>
|
||||
#define isinf !_finite
|
||||
#define isnan _isnan
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
#include "yajl/src/yajl.c"
|
||||
#include "yajl/src/yajl_alloc.c"
|
||||
#include "yajl/src/yajl_buf.c"
|
||||
#include "yajl/src/yajl_encode.c"
|
||||
#include "yajl/src/yajl_gen.c"
|
||||
#include "yajl/src/yajl_lex.c"
|
||||
#include "yajl/src/yajl_parser.c"
|
||||
#include "yajl/src/yajl_tree.c"
|
||||
#include "yajl/src/yajl_version.c"
|
||||
|
||||
#endif // TEST_YAJL
|
184
test/perftest/yajltest.cpp
Normal file
184
test/perftest/yajltest.cpp
Normal file
@ -0,0 +1,184 @@
|
||||
#include "perftest.h"
|
||||
|
||||
#if TEST_YAJL
|
||||
|
||||
extern "C" {
|
||||
#include "yajl/yajl_gen.h"
|
||||
#include "yajl/yajl_parse.h"
|
||||
#include "yajl/yajl_tree.h"
|
||||
};
|
||||
|
||||
class Yajl : public PerfTest {
|
||||
public:
|
||||
virtual void SetUp() {
|
||||
PerfTest::SetUp();
|
||||
root_ = yajl_tree_parse(json_, NULL, 0);
|
||||
ASSERT_TRUE(root_ != NULL);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
PerfTest::TearDown();
|
||||
yajl_tree_free(root_);
|
||||
}
|
||||
|
||||
protected:
|
||||
yajl_val root_;
|
||||
};
|
||||
|
||||
static int null_null(void *) { return 1; }
|
||||
static int null_boolean(void *, int) { return 1; }
|
||||
static int null_integer(void *, long long) { return 1; }
|
||||
static int null_double(void *, double) { return 1; }
|
||||
static int null_string(void *, const unsigned char*, size_t) { return 1; }
|
||||
static int null_start_map(void *) { return 1; }
|
||||
static int null_map_key(void *, const unsigned char*, size_t) { return 1; }
|
||||
static int null_end_map(void *) { return 1; }
|
||||
static int null_start_array(void*) { return 1; }
|
||||
static int null_end_array(void *) { return 1; }
|
||||
|
||||
static yajl_callbacks nullcallbacks = {
|
||||
null_null,
|
||||
null_boolean,
|
||||
null_integer,
|
||||
null_double,
|
||||
NULL, // yajl_number(). Here we want to test full-parsing performance.
|
||||
null_string,
|
||||
null_start_map,
|
||||
null_map_key,
|
||||
null_end_map,
|
||||
null_start_array,
|
||||
null_end_array
|
||||
};
|
||||
|
||||
TEST_F(Yajl, yajl_parse_nullcallbacks) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
yajl_handle hand = yajl_alloc(&nullcallbacks, NULL, NULL);
|
||||
yajl_status stat = yajl_parse(hand, (unsigned char*)json_, length_ - 1);
|
||||
//ASSERT_EQ(yajl_status_ok, stat);
|
||||
if (stat != yajl_status_ok) {
|
||||
unsigned char * str = yajl_get_error(hand, 1, (unsigned char*)json_, length_ + 1);
|
||||
fprintf(stderr, "%s", (const char *) str);
|
||||
}
|
||||
stat = yajl_complete_parse(hand);
|
||||
ASSERT_EQ(yajl_status_ok, stat);
|
||||
yajl_free(hand);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Yajl, yajl_tree_parse) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
yajl_val root = yajl_tree_parse(json_, NULL, 0);
|
||||
ASSERT_TRUE(root != NULL);
|
||||
yajl_tree_free(root);
|
||||
}
|
||||
}
|
||||
|
||||
yajl_gen_status GenVal(yajl_gen g, yajl_val v) {
|
||||
yajl_gen_status status;
|
||||
switch (v->type) {
|
||||
case yajl_t_string: return yajl_gen_string(g, (unsigned char*)v->u.string, strlen(v->u.string));
|
||||
|
||||
case yajl_t_number:
|
||||
{
|
||||
char buffer[100];
|
||||
char *num = buffer;
|
||||
size_t len;
|
||||
//if (YAJL_IS_INTEGER(v)) // buggy
|
||||
if (v->u.number.flags & YAJL_NUMBER_INT_VALID)
|
||||
len = sprintf(num, "%d", YAJL_GET_INTEGER(v));
|
||||
//else if (YAJL_IS_DOUBLE(v)) // buggy
|
||||
else if (v->u.number.flags & YAJL_NUMBER_DOUBLE_VALID)
|
||||
len = sprintf(num, "%g", YAJL_GET_DOUBLE(v));
|
||||
else {
|
||||
num = YAJL_GET_NUMBER(v);
|
||||
len = strlen(buffer);
|
||||
}
|
||||
return yajl_gen_number(g, num, len);
|
||||
}
|
||||
|
||||
case yajl_t_object:
|
||||
status = yajl_gen_map_open(g);
|
||||
if (status != yajl_gen_status_ok)
|
||||
return status;
|
||||
|
||||
for (size_t i = 0; i < v->u.object.len; i++) {
|
||||
status = yajl_gen_string(g, (unsigned char *)v->u.object.keys[i], strlen(v->u.object.keys[i]));
|
||||
if (status != yajl_gen_status_ok)
|
||||
return status;
|
||||
status = GenVal(g, v->u.object.values[i]);
|
||||
if (status != yajl_gen_status_ok)
|
||||
return status;
|
||||
}
|
||||
return yajl_gen_map_close(g);
|
||||
|
||||
case yajl_t_array:
|
||||
status = yajl_gen_array_open(g);
|
||||
if (status != yajl_gen_status_ok)
|
||||
return status;
|
||||
|
||||
for (size_t i = 0; i < v->u.array.len; i++) {
|
||||
status = GenVal(g, v->u.array.values[i]);
|
||||
if (status != yajl_gen_status_ok)
|
||||
return status;
|
||||
}
|
||||
|
||||
return yajl_gen_array_close(g);
|
||||
|
||||
case yajl_t_true: return yajl_gen_bool(g, 1);
|
||||
case yajl_t_false: return yajl_gen_bool(g, 0);
|
||||
case yajl_t_null: return yajl_gen_null(g);
|
||||
}
|
||||
return yajl_gen_in_error_state;
|
||||
}
|
||||
|
||||
TEST_F(Yajl, yajl_gen) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
yajl_gen g = yajl_gen_alloc(NULL);
|
||||
|
||||
yajl_gen_status status = GenVal(g, root_);
|
||||
if (status != yajl_gen_status_ok) {
|
||||
std::cout << "gen error: " << status << std::endl;
|
||||
FAIL();
|
||||
}
|
||||
|
||||
const unsigned char * buf;
|
||||
size_t len;
|
||||
status = yajl_gen_get_buf(g, &buf, &len);
|
||||
ASSERT_EQ(yajl_gen_status_ok, status);
|
||||
//if (i == 0)
|
||||
// std::cout << len << std::endl;
|
||||
yajl_gen_free(g);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Yajl, yajl_gen_beautify) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
yajl_gen g = yajl_gen_alloc(NULL);
|
||||
yajl_gen_config(g, yajl_gen_beautify, 1);
|
||||
yajl_gen_config(g, yajl_gen_indent_string, " ");
|
||||
|
||||
yajl_gen_status status = GenVal(g, root_);
|
||||
if (status != yajl_gen_status_ok) {
|
||||
std::cout << "gen error: " << status << std::endl;
|
||||
FAIL();
|
||||
}
|
||||
|
||||
const unsigned char * buf;
|
||||
size_t len;
|
||||
status = yajl_gen_get_buf(g, &buf, &len);
|
||||
ASSERT_EQ(yajl_gen_status_ok, status);
|
||||
//if (i == 0)
|
||||
// std::cout << len << std::endl;
|
||||
yajl_gen_free(g);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Yajl, Whitespace) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
yajl_val root = yajl_tree_parse(whitespace_, NULL, 0);
|
||||
ASSERT_TRUE(root != NULL);
|
||||
yajl_tree_free(root);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TEST_YAJL
|
67
test/unittest/documenttest.cpp
Normal file
67
test/unittest/documenttest.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
#include "unittest.h"
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/writer.h"
|
||||
#include <sstream>
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
TEST(Document, Parse) {
|
||||
Document doc;
|
||||
|
||||
doc.Parse<0>(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ");
|
||||
|
||||
EXPECT_TRUE(doc.IsObject());
|
||||
|
||||
EXPECT_TRUE(doc.HasMember("hello"));
|
||||
Value& hello = doc["hello"];
|
||||
EXPECT_TRUE(hello.IsString());
|
||||
EXPECT_STREQ("world", hello.GetString());
|
||||
|
||||
EXPECT_TRUE(doc.HasMember("t"));
|
||||
Value& t = doc["t"];
|
||||
EXPECT_TRUE(t.IsTrue());
|
||||
|
||||
EXPECT_TRUE(doc.HasMember("f"));
|
||||
Value& f = doc["f"];
|
||||
EXPECT_TRUE(f.IsFalse());
|
||||
|
||||
EXPECT_TRUE(doc.HasMember("n"));
|
||||
Value& n = doc["n"];
|
||||
EXPECT_TRUE(n.IsNull());
|
||||
|
||||
EXPECT_TRUE(doc.HasMember("i"));
|
||||
Value& i = doc["i"];
|
||||
EXPECT_TRUE(i.IsNumber());
|
||||
EXPECT_EQ(123, i.GetInt());
|
||||
|
||||
EXPECT_TRUE(doc.HasMember("pi"));
|
||||
Value& pi = doc["pi"];
|
||||
EXPECT_TRUE(pi.IsNumber());
|
||||
EXPECT_EQ(3.1416, pi.GetDouble());
|
||||
|
||||
EXPECT_TRUE(doc.HasMember("a"));
|
||||
Value& a = doc["a"];
|
||||
EXPECT_TRUE(a.IsArray());
|
||||
EXPECT_EQ(4, a.Size());
|
||||
for (SizeType i = 0; i < 4; i++)
|
||||
EXPECT_EQ(i + 1, a[i].GetUint());
|
||||
}
|
||||
|
||||
struct OutputStringStream : public std::ostringstream {
|
||||
typedef char Ch;
|
||||
|
||||
void Put(char c) {
|
||||
put(c);
|
||||
}
|
||||
};
|
||||
|
||||
TEST(Document, AcceptWriter) {
|
||||
Document doc;
|
||||
doc.Parse<0>(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ");
|
||||
|
||||
OutputStringStream os;
|
||||
Writer<OutputStringStream> writer(os);
|
||||
doc.Accept(writer);
|
||||
|
||||
EXPECT_EQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3,4]}", os.str());
|
||||
}
|
68
test/unittest/jsoncheckertest.cpp
Normal file
68
test/unittest/jsoncheckertest.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
#include "unittest.h"
|
||||
|
||||
#include "rapidjson/document.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
static char* ReadFile(const char* filename, size_t& length) {
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
if (!fp)
|
||||
fp = fopen(filename, "rb");
|
||||
if (!fp)
|
||||
return 0;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
length = (size_t)ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
char* json = (char*)malloc(length + 1);
|
||||
fread(json, 1, length, fp);
|
||||
json[length] = '\0';
|
||||
fclose(fp);
|
||||
return json;
|
||||
}
|
||||
|
||||
TEST(JsonChecker, Reader) {
|
||||
char filename[256];
|
||||
|
||||
// jsonchecker/failXX.json
|
||||
for (int i = 1; i <= 33; i++) {
|
||||
if (i == 18) // fail18.json is valid in rapidjson, which has no limitation on depth of nesting.
|
||||
continue;
|
||||
|
||||
sprintf(filename, "jsonchecker/fail%d.json", i);
|
||||
char* json;
|
||||
size_t length;
|
||||
if (!(json = ReadFile(filename, length))) {
|
||||
sprintf(filename, "../../bin/jsonchecker/fail%d.json", i);
|
||||
if (!(json = ReadFile(filename, length))) {
|
||||
printf("jsonchecker file %s not found", filename);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
|
||||
if (!document.Parse<0>((const char*)json).HasParseError())
|
||||
FAIL();
|
||||
//printf("%s(%u):%s\n", filename, (unsigned)document.GetErrorOffset(), document.GetParseError());
|
||||
free(json);
|
||||
}
|
||||
|
||||
// passX.json
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
sprintf(filename, "jsonchecker/pass%d.json", i);
|
||||
char* json;
|
||||
size_t length;
|
||||
if (!(json = ReadFile(filename, length))) {
|
||||
sprintf(filename, "../../bin/jsonchecker/pass%d.json", i);
|
||||
if (!(json = ReadFile(filename, length))) {
|
||||
printf("jsonchecker file %s not found", filename);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
|
||||
document.Parse<0>((const char*)json);
|
||||
EXPECT_TRUE(!document.HasParseError());
|
||||
free(json);
|
||||
}
|
||||
}
|
517
test/unittest/readertest.cpp
Normal file
517
test/unittest/readertest.cpp
Normal file
@ -0,0 +1,517 @@
|
||||
#include "unittest.h"
|
||||
|
||||
#define private public // For testing private members
|
||||
#include "rapidjson/reader.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
template<bool expect>
|
||||
struct ParseBoolHandler : BaseReaderHandler<> {
|
||||
ParseBoolHandler() : step_(0) {}
|
||||
void Default() { FAIL(); }
|
||||
void Bool(bool b) { EXPECT_EQ(expect, b); ++step_; }
|
||||
|
||||
unsigned step_;
|
||||
};
|
||||
|
||||
TEST(Reader, ParseTrue) {
|
||||
StringStream s("true");
|
||||
ParseBoolHandler<true> h;
|
||||
Reader reader;
|
||||
reader.ParseTrue<0>(s, h);
|
||||
EXPECT_EQ(1, h.step_);
|
||||
}
|
||||
|
||||
TEST(Reader, ParseFalse) {
|
||||
StringStream s("false");
|
||||
ParseBoolHandler<false> h;
|
||||
Reader reader;
|
||||
reader.ParseFalse<0>(s, h);
|
||||
EXPECT_EQ(1, h.step_);
|
||||
}
|
||||
|
||||
struct ParseIntHandler : BaseReaderHandler<> {
|
||||
ParseIntHandler() : step_(0) {}
|
||||
void Default() { FAIL(); }
|
||||
void Int(int i) { actual_ = i; step_++; }
|
||||
|
||||
unsigned step_;
|
||||
int actual_;
|
||||
};
|
||||
|
||||
struct ParseUintHandler : BaseReaderHandler<> {
|
||||
ParseUintHandler() : step_(0) {}
|
||||
void Default() { FAIL(); }
|
||||
void Uint(unsigned i) { actual_ = i; step_++; }
|
||||
|
||||
unsigned step_;
|
||||
unsigned actual_;
|
||||
};
|
||||
|
||||
struct ParseInt64Handler : BaseReaderHandler<> {
|
||||
ParseInt64Handler() : step_(0) {}
|
||||
void Default() { FAIL(); }
|
||||
void Int64(int64_t i) { actual_ = i; step_++; }
|
||||
|
||||
unsigned step_;
|
||||
int64_t actual_;
|
||||
};
|
||||
|
||||
struct ParseUint64Handler : BaseReaderHandler<> {
|
||||
ParseUint64Handler() : step_(0) {}
|
||||
void Default() { FAIL(); }
|
||||
void Uint64(uint64_t i) { actual_ = i; step_++; }
|
||||
|
||||
unsigned step_;
|
||||
uint64_t actual_;
|
||||
};
|
||||
|
||||
struct ParseDoubleHandler : BaseReaderHandler<> {
|
||||
ParseDoubleHandler() : step_(0) {}
|
||||
void Default() { FAIL(); }
|
||||
void Double(double d) { actual_ = d; step_++; }
|
||||
|
||||
unsigned step_;
|
||||
double actual_;
|
||||
};
|
||||
|
||||
TEST(Reader, ParseNumberHandler) {
|
||||
#define TEST_NUMBER(Handler, str, x) \
|
||||
{ \
|
||||
StringStream s(str); \
|
||||
Handler h; \
|
||||
Reader reader; \
|
||||
reader.ParseNumber<0>(s, h); \
|
||||
EXPECT_EQ(1, h.step_); \
|
||||
EXPECT_EQ(x, h.actual_); \
|
||||
}
|
||||
|
||||
#define TEST_DOUBLE(str, x) \
|
||||
{ \
|
||||
StringStream s(str); \
|
||||
ParseDoubleHandler h; \
|
||||
Reader reader; \
|
||||
reader.ParseNumber<0>(s, h); \
|
||||
EXPECT_EQ(1, h.step_); \
|
||||
EXPECT_DOUBLE_EQ(x, h.actual_); \
|
||||
}
|
||||
|
||||
TEST_NUMBER(ParseUintHandler, "0", 0);
|
||||
TEST_NUMBER(ParseUintHandler, "123", 123);
|
||||
TEST_NUMBER(ParseUintHandler, "2147483648", 2147483648u); // 2^31 - 1 (cannot be stored in int)
|
||||
TEST_NUMBER(ParseUintHandler, "4294967295", 4294967295u);
|
||||
|
||||
TEST_NUMBER(ParseIntHandler, "-123", -123);
|
||||
TEST_NUMBER(ParseIntHandler, "-2147483648", -2147483648LL); // -2^31 (min of int)
|
||||
|
||||
TEST_NUMBER(ParseUint64Handler, "4294967296", 4294967296ULL); // 2^32 (max of unsigned + 1, force to use uint64_t)
|
||||
TEST_NUMBER(ParseUint64Handler, "18446744073709551615", 18446744073709551615ULL); // 2^64 - 1 (max of uint64_t)
|
||||
|
||||
TEST_NUMBER(ParseInt64Handler, "-2147483649", -2147483649LL); // -2^31 -1 (min of int - 1, force to use int64_t)
|
||||
TEST_NUMBER(ParseInt64Handler, "-9223372036854775808", (-9223372036854775807LL - 1)); // -2^63 (min of int64_t)
|
||||
|
||||
TEST_DOUBLE("0.0", 0.0);
|
||||
TEST_DOUBLE("1.0", 1.0);
|
||||
TEST_DOUBLE("-1.0", -1.0);
|
||||
TEST_DOUBLE("1.5", 1.5);
|
||||
TEST_DOUBLE("-1.5", -1.5);
|
||||
TEST_DOUBLE("3.1416", 3.1416);
|
||||
TEST_DOUBLE("1E10", 1E10);
|
||||
TEST_DOUBLE("1e10", 1e10);
|
||||
TEST_DOUBLE("1E+10", 1E+10);
|
||||
TEST_DOUBLE("1E-10", 1E-10);
|
||||
TEST_DOUBLE("-1E10", -1E10);
|
||||
TEST_DOUBLE("-1e10", -1e10);
|
||||
TEST_DOUBLE("-1E+10", -1E+10);
|
||||
TEST_DOUBLE("-1E-10", -1E-10);
|
||||
TEST_DOUBLE("1.234E+10", 1.234E+10);
|
||||
TEST_DOUBLE("1.234E-10", 1.234E-10);
|
||||
TEST_DOUBLE("1.79769e+308", 1.79769e+308);
|
||||
//TEST_DOUBLE("2.22507e-308", 2.22507e-308); // TODO: underflow
|
||||
TEST_DOUBLE("-1.79769e+308", -1.79769e+308);
|
||||
//TEST_DOUBLE("-2.22507e-308", -2.22507e-308); // TODO: underflow
|
||||
TEST_DOUBLE("18446744073709551616", 18446744073709551616.0); // 2^64 (max of uint64_t + 1, force to use double)
|
||||
TEST_DOUBLE("-9223372036854775809", -9223372036854775809.0); // -2^63 - 1(min of int64_t + 1, force to use double)
|
||||
|
||||
{
|
||||
char n1e308[310]; // '1' followed by 308 '0'
|
||||
n1e308[0] = '1';
|
||||
for (int i = 1; i < 309; i++)
|
||||
n1e308[i] = '0';
|
||||
n1e308[309] = '\0';
|
||||
TEST_DOUBLE(n1e308, 1E308);
|
||||
}
|
||||
#undef TEST_NUMBER
|
||||
#undef TEST_DOUBLE
|
||||
}
|
||||
|
||||
TEST(Reader, ParseNumberHandler_Error) {
|
||||
#define TEST_NUMBER_ERROR(str) \
|
||||
{ \
|
||||
char buffer[1001]; \
|
||||
sprintf(buffer, "[%s]", str); \
|
||||
InsituStringStream s(buffer); \
|
||||
BaseReaderHandler<> h; \
|
||||
Reader reader; \
|
||||
EXPECT_FALSE(reader.Parse<0>(s, h)); \
|
||||
}
|
||||
|
||||
TEST_NUMBER_ERROR("a"); // At least one digit in integer part
|
||||
TEST_NUMBER_ERROR(".1"); // At least one digit in integer part
|
||||
|
||||
{
|
||||
char n1e309[311]; // '1' followed by 309 '0'
|
||||
n1e309[0] = '1';
|
||||
for (int i = 1; i < 310; i++)
|
||||
n1e309[i] = '0';
|
||||
n1e309[310] = '\0';
|
||||
TEST_NUMBER_ERROR(n1e309); // Number too big to store in double
|
||||
}
|
||||
|
||||
TEST_NUMBER_ERROR("1."); // At least one digit in fraction part
|
||||
TEST_NUMBER_ERROR("1e309"); // Number too big to store in double
|
||||
TEST_NUMBER_ERROR("1e_"); // At least one digit in exponent
|
||||
|
||||
#undef TEST_NUMBER_ERROR
|
||||
}
|
||||
|
||||
template <typename Encoding>
|
||||
struct ParseStringHandler : BaseReaderHandler<Encoding> {
|
||||
ParseStringHandler() : str_(0), length_(0) {}
|
||||
~ParseStringHandler() { EXPECT_TRUE(str_ != 0); if (copy_) free(const_cast<typename Encoding::Ch*>(str_)); }
|
||||
void Default() { FAIL(); }
|
||||
void String(const typename Encoding::Ch* str, size_t length, bool copy) {
|
||||
EXPECT_EQ(0, str_);
|
||||
if (copy) {
|
||||
str_ = (typename Encoding::Ch*)malloc((length + 1) * sizeof(typename Encoding::Ch));
|
||||
memcpy((void*)str_, str, (length + 1) * sizeof(typename Encoding::Ch));
|
||||
}
|
||||
else
|
||||
str_ = str;
|
||||
length_ = length;
|
||||
copy_ = copy;
|
||||
}
|
||||
|
||||
const typename Encoding::Ch* str_;
|
||||
size_t length_;
|
||||
bool copy_;
|
||||
};
|
||||
|
||||
TEST(Reader, ParseString) {
|
||||
#define TEST_STRING(Encoding, e, x) \
|
||||
{ \
|
||||
Encoding::Ch* buffer = StrDup(x); \
|
||||
GenericInsituStringStream<Encoding> is(buffer); \
|
||||
ParseStringHandler<Encoding> h; \
|
||||
GenericReader<Encoding> reader; \
|
||||
reader.ParseString<kParseInsituFlag>(is, h); \
|
||||
EXPECT_EQ(0, StrCmp<Encoding::Ch>(e, h.str_)); \
|
||||
EXPECT_EQ(StrLen(e), h.length_); \
|
||||
free(buffer); \
|
||||
GenericStringStream<Encoding> s(x); \
|
||||
ParseStringHandler<Encoding> h2; \
|
||||
GenericReader<Encoding> reader2; \
|
||||
reader2.ParseString<0>(s, h2); \
|
||||
EXPECT_EQ(0, StrCmp<Encoding::Ch>(e, h2.str_)); \
|
||||
EXPECT_EQ(StrLen(e), h2.length_); \
|
||||
}
|
||||
|
||||
// String constant L"\xXX" can only specify character code in bytes, which is not endianness-neutral.
|
||||
// And old compiler does not support u"" and U"" string literal. So here specify string literal by array of Ch.
|
||||
#define ARRAY(...) { __VA_ARGS__ }
|
||||
#define TEST_STRINGARRAY(Encoding, array, x) \
|
||||
{ \
|
||||
static const Encoding::Ch e[] = array; \
|
||||
TEST_STRING(Encoding, e, x); \
|
||||
}
|
||||
|
||||
#define TEST_STRINGARRAY2(Encoding, earray, xarray) \
|
||||
{ \
|
||||
static const Encoding::Ch e[] = earray; \
|
||||
static const Encoding::Ch x[] = xarray; \
|
||||
TEST_STRING(Encoding, e, x); \
|
||||
}
|
||||
|
||||
TEST_STRING(UTF8<>, "", "\"\"");
|
||||
TEST_STRING(UTF8<>, "Hello", "\"Hello\"");
|
||||
TEST_STRING(UTF8<>, "Hello\nWorld", "\"Hello\\nWorld\"");
|
||||
TEST_STRING(UTF8<>, "\"\\/\b\f\n\r\t", "\"\\\"\\\\/\\b\\f\\n\\r\\t\"");
|
||||
TEST_STRING(UTF8<>, "\x24", "\"\\u0024\""); // Dollar sign U+0024
|
||||
TEST_STRING(UTF8<>, "\xC2\xA2", "\"\\u00A2\""); // Cents sign U+00A2
|
||||
TEST_STRING(UTF8<>, "\xE2\x82\xAC", "\"\\u20AC\""); // Euro sign U+20AC
|
||||
TEST_STRING(UTF8<>, "\xF0\x9D\x84\x9E", "\"\\uD834\\uDD1E\""); // G clef sign U+1D11E
|
||||
|
||||
// UTF16
|
||||
TEST_STRING(UTF16<>, L"", L"\"\"");
|
||||
TEST_STRING(UTF16<>, L"Hello", L"\"Hello\"");
|
||||
TEST_STRING(UTF16<>, L"Hello\nWorld", L"\"Hello\\nWorld\"");
|
||||
TEST_STRING(UTF16<>, L"\"\\/\b\f\n\r\t", L"\"\\\"\\\\/\\b\\f\\n\\r\\t\"");
|
||||
TEST_STRINGARRAY(UTF16<>, ARRAY(0x0024, 0x0000), L"\"\\u0024\"");
|
||||
TEST_STRINGARRAY(UTF16<>, ARRAY(0x00A2, 0x0000), L"\"\\u00A2\""); // Cents sign U+00A2
|
||||
TEST_STRINGARRAY(UTF16<>, ARRAY(0x20AC, 0x0000), L"\"\\u20AC\""); // Euro sign U+20AC
|
||||
TEST_STRINGARRAY(UTF16<>, ARRAY(0xD834, 0xDD1E, 0x0000), L"\"\\uD834\\uDD1E\""); // G clef sign U+1D11E
|
||||
|
||||
// UTF32
|
||||
TEST_STRINGARRAY2(UTF32<>, ARRAY('\0'), ARRAY('\"', '\"', '\0'));
|
||||
TEST_STRINGARRAY2(UTF32<>, ARRAY('H', 'e', 'l', 'l', 'o', '\0'), ARRAY('\"', 'H', 'e', 'l', 'l', 'o', '\"', '\0'));
|
||||
TEST_STRINGARRAY2(UTF32<>, ARRAY('H', 'e', 'l', 'l', 'o', '\n', 'W', 'o', 'r', 'l', 'd', '\0'), ARRAY('\"', 'H', 'e', 'l', 'l', 'o', '\\', 'n', 'W', 'o', 'r', 'l', 'd', '\"', '\0'));
|
||||
TEST_STRINGARRAY2(UTF32<>, ARRAY('\"', '\\', '/', '\b', '\f', '\n', '\r', '\t', '\0'), ARRAY('\"', '\\', '\"', '\\', '\\', '/', '\\', 'b', '\\', 'f', '\\', 'n', '\\', 'r', '\\', 't', '\"', '\0'));
|
||||
TEST_STRINGARRAY2(UTF32<>, ARRAY(0x00024, 0x0000), ARRAY('\"', '\\', 'u', '0', '0', '2', '4', '\"', '\0'));
|
||||
TEST_STRINGARRAY2(UTF32<>, ARRAY(0x000A2, 0x0000), ARRAY('\"', '\\', 'u', '0', '0', 'A', '2', '\"', '\0')); // Cents sign U+00A2
|
||||
TEST_STRINGARRAY2(UTF32<>, ARRAY(0x020AC, 0x0000), ARRAY('\"', '\\', 'u', '2', '0', 'A', 'C', '\"', '\0')); // Euro sign U+20AC
|
||||
TEST_STRINGARRAY2(UTF32<>, ARRAY(0x1D11E, 0x0000), ARRAY('\"', '\\', 'u', 'D', '8', '3', '4', '\\', 'u', 'D', 'D', '1', 'E', '\"', '\0')); // G clef sign U+1D11E
|
||||
|
||||
#undef TEST_STRINGARRAY
|
||||
#undef ARRAY
|
||||
#undef TEST_STRING
|
||||
|
||||
// Support of null character in string
|
||||
{
|
||||
StringStream s("\"Hello\\u0000World\"");
|
||||
const char e[] = "Hello\0World";
|
||||
ParseStringHandler<UTF8<> > h;
|
||||
Reader reader;
|
||||
reader.ParseString<0>(s, h);
|
||||
EXPECT_EQ(0, memcmp(e, h.str_, h.length_ + 1));
|
||||
EXPECT_EQ(11, h.length_);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Reader, ParseString_NonDestructive) {
|
||||
StringStream s("\"Hello\\nWorld\"");
|
||||
ParseStringHandler<UTF8<> > h;
|
||||
Reader reader;
|
||||
reader.ParseString<0>(s, h);
|
||||
EXPECT_EQ(0, StrCmp("Hello\nWorld", h.str_));
|
||||
EXPECT_EQ(11, h.length_);
|
||||
}
|
||||
|
||||
#ifdef RAPIDJSON_USE_EXCEPTION
|
||||
TEST(Reader, ParseString_Error) {
|
||||
#define TEST_STRING_ERROR(str) \
|
||||
{ \
|
||||
char buffer[1001]; \
|
||||
strncpy(buffer, str, 1000); \
|
||||
InsituStringStream s(buffer); \
|
||||
BaseReaderHandler<> h; \
|
||||
Reader reader; \
|
||||
EXPECT_ERROR(reader.ParseString<0>(s, h), ParseException); \
|
||||
}
|
||||
|
||||
TEST_STRING_ERROR("\"\\a\""); // Unknown escape character
|
||||
TEST_STRING_ERROR("\"\\uABCG\""); // Incorrect hex digit after \\u escape
|
||||
TEST_STRING_ERROR("\"\\uD800X\""); // Missing the second \\u in surrogate pair
|
||||
TEST_STRING_ERROR("\"\\uD800\\uFFFF\""); // The second \\u in surrogate pair is invalid
|
||||
TEST_STRING_ERROR("\"Test"); // lacks ending quotation before the end of string
|
||||
|
||||
#undef TEST_STRING_ERROR
|
||||
}
|
||||
#endif // RAPIDJSON_USE_EXCEPTION
|
||||
|
||||
template <unsigned count>
|
||||
struct ParseArrayHandler : BaseReaderHandler<> {
|
||||
ParseArrayHandler() : step_(0) {}
|
||||
|
||||
void Default() { FAIL(); }
|
||||
void Uint(unsigned i) { EXPECT_EQ(step_, i); step_++; }
|
||||
void StartArray() { EXPECT_EQ(0, step_); step_++; }
|
||||
void EndArray(SizeType elementCount) { step_++; }
|
||||
|
||||
unsigned step_;
|
||||
};
|
||||
|
||||
TEST(Reader, ParseEmptyArray) {
|
||||
char *json = StrDup("[ ] ");
|
||||
InsituStringStream s(json);
|
||||
ParseArrayHandler<0> h;
|
||||
Reader reader;
|
||||
reader.ParseArray<0>(s, h);
|
||||
EXPECT_EQ(2, h.step_);
|
||||
free(json);
|
||||
}
|
||||
|
||||
TEST(Reader, ParseArray) {
|
||||
char *json = StrDup("[1, 2, 3, 4]");
|
||||
InsituStringStream s(json);
|
||||
ParseArrayHandler<4> h;
|
||||
Reader reader;
|
||||
reader.ParseArray<0>(s, h);
|
||||
EXPECT_EQ(6, h.step_);
|
||||
free(json);
|
||||
}
|
||||
|
||||
#ifdef RAPIDJSON_USE_EXCEPTION
|
||||
TEST(Reader, ParseArray_Error) {
|
||||
#define TEST_ARRAY_ERROR(str) \
|
||||
{ \
|
||||
char buffer[1001]; \
|
||||
strncpy(buffer, str, 1000); \
|
||||
InsituStringStream s(buffer); \
|
||||
BaseReaderHandler<> h; \
|
||||
Reader<UTF8<>, CrtAllocator> reader; \
|
||||
EXPECT_ERROR(reader.ParseArray<0>(s, h), ParseException); \
|
||||
}
|
||||
|
||||
// Must be a comma or ']' after an array element.
|
||||
TEST_ARRAY_ERROR("[");
|
||||
TEST_ARRAY_ERROR("[}");
|
||||
TEST_ARRAY_ERROR("[1 2]");
|
||||
|
||||
#undef TEST_ARRAY_ERROR
|
||||
}
|
||||
#endif // RAPIDJSON_USE_EXCEPTION
|
||||
|
||||
struct ParseObjectHandler : BaseReaderHandler<> {
|
||||
ParseObjectHandler() : step_(0) {}
|
||||
|
||||
void Null() { EXPECT_EQ(8, step_); step_++; }
|
||||
void Bool(bool b) {
|
||||
switch(step_) {
|
||||
case 4: EXPECT_TRUE(b); step_++; break;
|
||||
case 6: EXPECT_FALSE(b); step_++; break;
|
||||
default: FAIL();
|
||||
}
|
||||
}
|
||||
void Int(int i) {
|
||||
switch(step_) {
|
||||
case 10: EXPECT_EQ(123, i); step_++; break;
|
||||
case 15: EXPECT_EQ(1, i); step_++; break;
|
||||
case 16: EXPECT_EQ(2, i); step_++; break;
|
||||
case 17: EXPECT_EQ(3, i); step_++; break;
|
||||
default: FAIL();
|
||||
}
|
||||
}
|
||||
void Uint(unsigned i) { Int(i); }
|
||||
void Double(double d) { EXPECT_EQ(12, step_); EXPECT_EQ(3.1416, d); step_++; }
|
||||
void String(const char* str, size_t length, bool copy) {
|
||||
switch(step_) {
|
||||
case 1: EXPECT_STREQ("hello", str); step_++; break;
|
||||
case 2: EXPECT_STREQ("world", str); step_++; break;
|
||||
case 3: EXPECT_STREQ("t", str); step_++; break;
|
||||
case 5: EXPECT_STREQ("f", str); step_++; break;
|
||||
case 7: EXPECT_STREQ("n", str); step_++; break;
|
||||
case 9: EXPECT_STREQ("i", str); step_++; break;
|
||||
case 11: EXPECT_STREQ("pi", str); step_++; break;
|
||||
case 13: EXPECT_STREQ("a", str); step_++; break;
|
||||
default: FAIL();
|
||||
}
|
||||
}
|
||||
void StartObject() { EXPECT_EQ(0, step_); step_++; }
|
||||
void EndObject(SizeType memberCount) { EXPECT_EQ(19, step_); EXPECT_EQ(7, memberCount); step_++;}
|
||||
void StartArray() { EXPECT_EQ(14, step_); step_++; }
|
||||
void EndArray(SizeType elementCount) { EXPECT_EQ(18, step_); EXPECT_EQ(3, elementCount); step_++;}
|
||||
|
||||
unsigned step_;
|
||||
};
|
||||
|
||||
TEST(Reader, ParseObject) {
|
||||
const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } ";
|
||||
|
||||
// Insitu
|
||||
{
|
||||
char* json2 = StrDup(json);
|
||||
InsituStringStream s(json2);
|
||||
ParseObjectHandler h;
|
||||
Reader reader;
|
||||
reader.ParseObject<kParseInsituFlag>(s, h);
|
||||
EXPECT_EQ(20, h.step_);
|
||||
free(json2);
|
||||
}
|
||||
|
||||
// Normal
|
||||
{
|
||||
StringStream s(json);
|
||||
ParseObjectHandler h;
|
||||
Reader reader;
|
||||
reader.ParseObject<0>(s, h);
|
||||
EXPECT_EQ(20, h.step_);
|
||||
}
|
||||
}
|
||||
|
||||
struct ParseEmptyObjectHandler : BaseReaderHandler<> {
|
||||
ParseEmptyObjectHandler() : step_(0) {}
|
||||
|
||||
void Default() { FAIL(); }
|
||||
void StartObject() { EXPECT_EQ(0, step_); step_++; }
|
||||
void EndObject(SizeType memberCount) { EXPECT_EQ(1, step_); step_++; }
|
||||
|
||||
unsigned step_;
|
||||
};
|
||||
|
||||
TEST(Reader, Parse_EmptyObject) {
|
||||
StringStream s("{ } ");
|
||||
ParseEmptyObjectHandler h;
|
||||
Reader reader;
|
||||
reader.ParseObject<0>(s, h);
|
||||
EXPECT_EQ(2, h.step_);
|
||||
}
|
||||
|
||||
#ifdef RAPIDJSON_USE_EXCEPTION
|
||||
TEST(Reader, ParseObject_Error) {
|
||||
#define TEST_OBJECT_ERROR(str) \
|
||||
{ \
|
||||
char buffer[1001]; \
|
||||
strncpy(buffer, str, 1000); \
|
||||
InsituStringStream s(buffer); \
|
||||
BaseReaderHandler<> h; \
|
||||
Reader<UTF8<>, CrtAllocator> reader; \
|
||||
EXPECT_ERROR(reader.ParseObject<0>(s, h), ParseException); \
|
||||
}
|
||||
|
||||
// Name of an object member must be a string
|
||||
TEST_OBJECT_ERROR("{null:1}");
|
||||
TEST_OBJECT_ERROR("{true:1}");
|
||||
TEST_OBJECT_ERROR("{false:1}");
|
||||
TEST_OBJECT_ERROR("{1:1}");
|
||||
TEST_OBJECT_ERROR("{[]:1}");
|
||||
TEST_OBJECT_ERROR("{{}:1}");
|
||||
TEST_OBJECT_ERROR("{xyz:1}");
|
||||
|
||||
// There must be a colon after the name of object member
|
||||
TEST_OBJECT_ERROR("{\"a\" 1}");
|
||||
TEST_OBJECT_ERROR("{\"a\",1}");
|
||||
|
||||
// Must be a comma or '}' after an object member
|
||||
TEST_OBJECT_ERROR("{]");
|
||||
TEST_OBJECT_ERROR("{\"a\":1]");
|
||||
|
||||
#undef TEST_OBJECT_ERROR
|
||||
}
|
||||
#endif // RAPIDJSON_USE_EXCEPTION
|
||||
|
||||
#ifdef RAPIDJSON_USE_EXCEPTION
|
||||
TEST(Reader, Parse_Error) {
|
||||
#define TEST_ERROR(str) \
|
||||
{ \
|
||||
char buffer[1001]; \
|
||||
strncpy(buffer, str, 1000); \
|
||||
InsituStringStream s(buffer); \
|
||||
BaseReaderHandler<> h; \
|
||||
Reader reader; \
|
||||
EXPECT_ERROR(reader.Parse<0>(s, h), ParseException); \
|
||||
}
|
||||
|
||||
// Text only contains white space(s)
|
||||
TEST_ERROR("");
|
||||
TEST_ERROR(" ");
|
||||
TEST_ERROR(" \n");
|
||||
|
||||
// Expect either an object or array at root
|
||||
TEST_ERROR("null");
|
||||
TEST_ERROR("true");
|
||||
TEST_ERROR("false");
|
||||
TEST_ERROR("\"s\"");
|
||||
TEST_ERROR("0");
|
||||
|
||||
// Nothing should follow the root object or array
|
||||
TEST_ERROR("[] 0");
|
||||
TEST_ERROR("{} 0");
|
||||
|
||||
// Invalid value
|
||||
TEST_ERROR("nulL");
|
||||
TEST_ERROR("truE");
|
||||
TEST_ERROR("falsE");
|
||||
|
||||
#undef TEST_ERROR
|
||||
}
|
||||
#endif // RAPIDJSON_USE_EXCEPTION
|
10
test/unittest/unittest.cpp
Normal file
10
test/unittest/unittest.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
#include "unittest.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
#if _MSC_VER
|
||||
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
|
||||
//void *testWhetherMemoryLeakDetectionWorks = malloc(1);
|
||||
#endif
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
33
test/unittest/unittest.h
Normal file
33
test/unittest/unittest.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef UNITTEST_H_
|
||||
#define UNITTEST_H_
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
#include <crtdbg.h>
|
||||
#pragma warning(disable : 4996) // 'function': was declared deprecated
|
||||
#endif
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
template <typename Ch>
|
||||
inline size_t StrLen(const Ch* s) {
|
||||
const Ch* p = s;
|
||||
while (*p) p++;
|
||||
return p - s;
|
||||
}
|
||||
|
||||
template<typename Ch>
|
||||
inline int StrCmp(const Ch* s1, const Ch* s2) {
|
||||
while(*s1 && (*s1 == *s2)) { s1++; s2++; }
|
||||
return (unsigned)*s1 < (unsigned)*s2 ? -1 : (unsigned)*s1 > (unsigned)*s2;
|
||||
}
|
||||
|
||||
template <typename Ch>
|
||||
inline Ch* StrDup(const Ch* str) {
|
||||
size_t bufferSize = sizeof(Ch) * (StrLen(str) + 1);
|
||||
Ch* buffer = (Ch*)malloc(bufferSize);
|
||||
memcpy(buffer, str, bufferSize);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
#endif // UNITTEST_H_
|
578
test/unittest/valuetest.cpp
Normal file
578
test/unittest/valuetest.cpp
Normal file
@ -0,0 +1,578 @@
|
||||
#include "unittest.h"
|
||||
#include "rapidjson/document.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
TEST(Value, default_constructor) {
|
||||
Value x;
|
||||
EXPECT_EQ(kNullType, x.GetType());
|
||||
EXPECT_TRUE(x.IsNull());
|
||||
|
||||
//std::cout << "sizeof(Value): " << sizeof(x) << std::endl;
|
||||
}
|
||||
|
||||
// Should not pass compilation
|
||||
//TEST(Value, copy_constructor) {
|
||||
// Value x(1234);
|
||||
// Value y = x;
|
||||
//}
|
||||
|
||||
TEST(Value, assignment_operator) {
|
||||
Value x(1234);
|
||||
Value y;
|
||||
y = x;
|
||||
EXPECT_TRUE(x.IsNull()); // move semantic
|
||||
EXPECT_EQ(1234, y.GetInt());
|
||||
}
|
||||
|
||||
|
||||
TEST(Value, Null) {
|
||||
// Default constructor
|
||||
Value x;
|
||||
EXPECT_EQ(kNullType, x.GetType());
|
||||
EXPECT_TRUE(x.IsNull());
|
||||
|
||||
EXPECT_FALSE(x.IsTrue());
|
||||
EXPECT_FALSE(x.IsFalse());
|
||||
EXPECT_FALSE(x.IsNumber());
|
||||
EXPECT_FALSE(x.IsString());
|
||||
EXPECT_FALSE(x.IsObject());
|
||||
EXPECT_FALSE(x.IsArray());
|
||||
|
||||
// Constructor with type
|
||||
Value y(kNullType);
|
||||
EXPECT_TRUE(y.IsNull());
|
||||
|
||||
// SetNull();
|
||||
Value z(true);
|
||||
z.SetNull();
|
||||
EXPECT_TRUE(z.IsNull());
|
||||
}
|
||||
|
||||
TEST(Value, True) {
|
||||
// Constructor with bool
|
||||
Value x(true);
|
||||
EXPECT_EQ(kTrueType, x.GetType());
|
||||
EXPECT_TRUE(x.GetBool());
|
||||
EXPECT_TRUE(x.IsBool());
|
||||
EXPECT_TRUE(x.IsTrue());
|
||||
|
||||
EXPECT_FALSE(x.IsNull());
|
||||
EXPECT_FALSE(x.IsFalse());
|
||||
EXPECT_FALSE(x.IsNumber());
|
||||
EXPECT_FALSE(x.IsString());
|
||||
EXPECT_FALSE(x.IsObject());
|
||||
EXPECT_FALSE(x.IsArray());
|
||||
|
||||
// Constructor with type
|
||||
Value y(kTrueType);
|
||||
EXPECT_TRUE(y.IsTrue());
|
||||
|
||||
// SetBool()
|
||||
Value z;
|
||||
z.SetBool(true);
|
||||
EXPECT_TRUE(z.IsTrue());
|
||||
}
|
||||
|
||||
TEST(Value, False) {
|
||||
// Constructor with bool
|
||||
Value x(false);
|
||||
EXPECT_EQ(kFalseType, x.GetType());
|
||||
EXPECT_TRUE(x.IsBool());
|
||||
EXPECT_TRUE(x.IsFalse());
|
||||
|
||||
EXPECT_FALSE(x.IsNull());
|
||||
EXPECT_FALSE(x.IsTrue());
|
||||
EXPECT_FALSE(x.GetBool());
|
||||
//EXPECT_FALSE((bool)x);
|
||||
EXPECT_FALSE(x.IsNumber());
|
||||
EXPECT_FALSE(x.IsString());
|
||||
EXPECT_FALSE(x.IsObject());
|
||||
EXPECT_FALSE(x.IsArray());
|
||||
|
||||
// Constructor with type
|
||||
Value y(kFalseType);
|
||||
EXPECT_TRUE(y.IsFalse());
|
||||
|
||||
// SetBool()
|
||||
Value z;
|
||||
z.SetBool(false);
|
||||
EXPECT_TRUE(z.IsFalse());
|
||||
}
|
||||
|
||||
TEST(Value, Int) {
|
||||
// Constructor with int
|
||||
Value x(1234);
|
||||
EXPECT_EQ(kNumberType, x.GetType());
|
||||
EXPECT_EQ(1234, x.GetInt());
|
||||
EXPECT_EQ(1234, x.GetUint());
|
||||
EXPECT_EQ(1234, x.GetInt64());
|
||||
EXPECT_EQ(1234, x.GetUint64());
|
||||
EXPECT_EQ(1234, x.GetDouble());
|
||||
//EXPECT_EQ(1234, (int)x);
|
||||
//EXPECT_EQ(1234, (unsigned)x);
|
||||
//EXPECT_EQ(1234, (int64_t)x);
|
||||
//EXPECT_EQ(1234, (uint64_t)x);
|
||||
//EXPECT_EQ(1234, (double)x);
|
||||
EXPECT_TRUE(x.IsNumber());
|
||||
EXPECT_TRUE(x.IsInt());
|
||||
EXPECT_TRUE(x.IsUint());
|
||||
EXPECT_TRUE(x.IsInt64());
|
||||
EXPECT_TRUE(x.IsUint64());
|
||||
|
||||
EXPECT_FALSE(x.IsDouble());
|
||||
EXPECT_FALSE(x.IsNull());
|
||||
EXPECT_FALSE(x.IsBool());
|
||||
EXPECT_FALSE(x.IsFalse());
|
||||
EXPECT_FALSE(x.IsTrue());
|
||||
EXPECT_FALSE(x.IsString());
|
||||
EXPECT_FALSE(x.IsObject());
|
||||
EXPECT_FALSE(x.IsArray());
|
||||
|
||||
Value nx(-1234);
|
||||
EXPECT_EQ(-1234, nx.GetInt());
|
||||
EXPECT_EQ(-1234, nx.GetInt64());
|
||||
EXPECT_TRUE(nx.IsInt());
|
||||
EXPECT_TRUE(nx.IsInt64());
|
||||
EXPECT_FALSE(nx.IsUint());
|
||||
EXPECT_FALSE(nx.IsUint64());
|
||||
|
||||
// Constructor with type
|
||||
Value y(kNumberType);
|
||||
EXPECT_TRUE(y.IsNumber());
|
||||
EXPECT_TRUE(y.IsInt());
|
||||
EXPECT_EQ(0, y.GetInt());
|
||||
|
||||
// SetInt()
|
||||
Value z;
|
||||
z.SetInt(1234);
|
||||
EXPECT_EQ(1234, z.GetInt());
|
||||
|
||||
// operator=(int)
|
||||
z = 5678;
|
||||
EXPECT_EQ(5678, z.GetInt());
|
||||
}
|
||||
|
||||
TEST(Value, Uint) {
|
||||
// Constructor with int
|
||||
Value x(1234u);
|
||||
EXPECT_EQ(kNumberType, x.GetType());
|
||||
EXPECT_EQ(1234u, x.GetInt());
|
||||
EXPECT_EQ(1234u, x.GetUint());
|
||||
EXPECT_EQ(1234u, x.GetInt64());
|
||||
EXPECT_EQ(1234u, x.GetUint64());
|
||||
EXPECT_TRUE(x.IsNumber());
|
||||
EXPECT_TRUE(x.IsInt());
|
||||
EXPECT_TRUE(x.IsUint());
|
||||
EXPECT_TRUE(x.IsInt64());
|
||||
EXPECT_TRUE(x.IsUint64());
|
||||
EXPECT_EQ(1234.0, x.GetDouble()); // Number can always be cast as double but !IsDouble().
|
||||
|
||||
EXPECT_FALSE(x.IsDouble());
|
||||
EXPECT_FALSE(x.IsNull());
|
||||
EXPECT_FALSE(x.IsBool());
|
||||
EXPECT_FALSE(x.IsFalse());
|
||||
EXPECT_FALSE(x.IsTrue());
|
||||
EXPECT_FALSE(x.IsString());
|
||||
EXPECT_FALSE(x.IsObject());
|
||||
EXPECT_FALSE(x.IsArray());
|
||||
|
||||
// SetUint()
|
||||
Value z;
|
||||
z.SetUint(1234);
|
||||
EXPECT_EQ(1234, z.GetUint());
|
||||
|
||||
// operator=(unsigned)
|
||||
z = 5678u;
|
||||
EXPECT_EQ(5678, z.GetUint());
|
||||
|
||||
z = 2147483648u; // 2^31, cannot cast as int
|
||||
EXPECT_EQ(2147483648u, z.GetUint());
|
||||
EXPECT_FALSE(z.IsInt());
|
||||
}
|
||||
|
||||
TEST(Value, Int64) {
|
||||
// Constructor with int
|
||||
Value x(1234LL);
|
||||
EXPECT_EQ(kNumberType, x.GetType());
|
||||
EXPECT_EQ(1234, x.GetInt());
|
||||
EXPECT_EQ(1234, x.GetUint());
|
||||
EXPECT_EQ(1234, x.GetInt64());
|
||||
EXPECT_EQ(1234, x.GetUint64());
|
||||
EXPECT_TRUE(x.IsNumber());
|
||||
EXPECT_TRUE(x.IsInt());
|
||||
EXPECT_TRUE(x.IsUint());
|
||||
EXPECT_TRUE(x.IsInt64());
|
||||
EXPECT_TRUE(x.IsUint64());
|
||||
|
||||
EXPECT_FALSE(x.IsDouble());
|
||||
EXPECT_FALSE(x.IsNull());
|
||||
EXPECT_FALSE(x.IsBool());
|
||||
EXPECT_FALSE(x.IsFalse());
|
||||
EXPECT_FALSE(x.IsTrue());
|
||||
EXPECT_FALSE(x.IsString());
|
||||
EXPECT_FALSE(x.IsObject());
|
||||
EXPECT_FALSE(x.IsArray());
|
||||
|
||||
Value nx(-1234LL);
|
||||
EXPECT_EQ(-1234, nx.GetInt());
|
||||
EXPECT_EQ(-1234, nx.GetInt64());
|
||||
EXPECT_TRUE(nx.IsInt());
|
||||
EXPECT_TRUE(nx.IsInt64());
|
||||
EXPECT_FALSE(nx.IsUint());
|
||||
EXPECT_FALSE(nx.IsUint64());
|
||||
|
||||
// SetInt64()
|
||||
Value z;
|
||||
z.SetInt64(1234);
|
||||
EXPECT_EQ(1234, z.GetInt64());
|
||||
|
||||
z.SetInt64(2147483648LL); // 2^31, cannot cast as int
|
||||
EXPECT_FALSE(z.IsInt());
|
||||
EXPECT_TRUE(z.IsUint());
|
||||
|
||||
z.SetInt64(4294967296LL); // 2^32, cannot cast as uint
|
||||
EXPECT_FALSE(z.IsInt());
|
||||
EXPECT_FALSE(z.IsUint());
|
||||
}
|
||||
|
||||
TEST(Value, Uint64) {
|
||||
// Constructor with int
|
||||
Value x(1234LL);
|
||||
EXPECT_EQ(kNumberType, x.GetType());
|
||||
EXPECT_EQ(1234, x.GetInt());
|
||||
EXPECT_EQ(1234, x.GetUint());
|
||||
EXPECT_EQ(1234, x.GetInt64());
|
||||
EXPECT_EQ(1234, x.GetUint64());
|
||||
EXPECT_TRUE(x.IsNumber());
|
||||
EXPECT_TRUE(x.IsInt());
|
||||
EXPECT_TRUE(x.IsUint());
|
||||
EXPECT_TRUE(x.IsInt64());
|
||||
EXPECT_TRUE(x.IsUint64());
|
||||
|
||||
EXPECT_FALSE(x.IsDouble());
|
||||
EXPECT_FALSE(x.IsNull());
|
||||
EXPECT_FALSE(x.IsBool());
|
||||
EXPECT_FALSE(x.IsFalse());
|
||||
EXPECT_FALSE(x.IsTrue());
|
||||
EXPECT_FALSE(x.IsString());
|
||||
EXPECT_FALSE(x.IsObject());
|
||||
EXPECT_FALSE(x.IsArray());
|
||||
|
||||
// SetUint64()
|
||||
Value z;
|
||||
z.SetUint64(1234);
|
||||
EXPECT_EQ(1234, z.GetUint64());
|
||||
|
||||
z.SetUint64(2147483648LL); // 2^31, cannot cast as int
|
||||
EXPECT_FALSE(z.IsInt());
|
||||
EXPECT_TRUE(z.IsUint());
|
||||
EXPECT_TRUE(z.IsInt64());
|
||||
|
||||
z.SetUint64(4294967296LL); // 2^32, cannot cast as uint
|
||||
EXPECT_FALSE(z.IsInt());
|
||||
EXPECT_FALSE(z.IsUint());
|
||||
EXPECT_TRUE(z.IsInt64());
|
||||
|
||||
z.SetUint64(9223372036854775808uLL); // 2^63 cannot cast as int64
|
||||
EXPECT_FALSE(z.IsInt64());
|
||||
}
|
||||
|
||||
TEST(Value, Double) {
|
||||
// Constructor with double
|
||||
Value x(12.34);
|
||||
EXPECT_EQ(kNumberType, x.GetType());
|
||||
EXPECT_EQ(12.34, x.GetDouble());
|
||||
EXPECT_TRUE(x.IsNumber());
|
||||
EXPECT_TRUE(x.IsDouble());
|
||||
|
||||
EXPECT_FALSE(x.IsInt());
|
||||
EXPECT_FALSE(x.IsNull());
|
||||
EXPECT_FALSE(x.IsBool());
|
||||
EXPECT_FALSE(x.IsFalse());
|
||||
EXPECT_FALSE(x.IsTrue());
|
||||
EXPECT_FALSE(x.IsString());
|
||||
EXPECT_FALSE(x.IsObject());
|
||||
EXPECT_FALSE(x.IsArray());
|
||||
|
||||
// SetDouble()
|
||||
Value z;
|
||||
z.SetDouble(12.34);
|
||||
EXPECT_EQ(12.34, z.GetDouble());
|
||||
|
||||
z = 56.78;
|
||||
EXPECT_EQ(56.78, z.GetDouble());
|
||||
}
|
||||
|
||||
TEST(Value, String) {
|
||||
// Constructor with const string
|
||||
Value x("Hello", 5);
|
||||
EXPECT_EQ(kStringType, x.GetType());
|
||||
EXPECT_TRUE(x.IsString());
|
||||
EXPECT_STREQ("Hello", x.GetString());
|
||||
EXPECT_EQ(5, x.GetStringLength());
|
||||
|
||||
EXPECT_FALSE(x.IsNumber());
|
||||
EXPECT_FALSE(x.IsNull());
|
||||
EXPECT_FALSE(x.IsBool());
|
||||
EXPECT_FALSE(x.IsFalse());
|
||||
EXPECT_FALSE(x.IsTrue());
|
||||
EXPECT_FALSE(x.IsObject());
|
||||
EXPECT_FALSE(x.IsArray());
|
||||
|
||||
// Constructor with copy string
|
||||
MemoryPoolAllocator<> allocator;
|
||||
Value c(x.GetString(), x.GetStringLength(), allocator);
|
||||
//x.SetString("World");
|
||||
x.SetString("World", 5);
|
||||
EXPECT_STREQ("Hello", c.GetString());
|
||||
EXPECT_EQ(5, c.GetStringLength());
|
||||
|
||||
// Constructor with type
|
||||
Value y(kStringType);
|
||||
EXPECT_TRUE(y.IsString());
|
||||
EXPECT_EQ(0, y.GetString());
|
||||
EXPECT_EQ(0, y.GetStringLength());
|
||||
|
||||
// SetConsttring()
|
||||
Value z;
|
||||
//z.SetString("Hello");
|
||||
z.SetString("Hello", 5);
|
||||
EXPECT_STREQ("Hello", z.GetString());
|
||||
EXPECT_EQ(5, z.GetStringLength());
|
||||
|
||||
// SetString()
|
||||
char s[] = "World";
|
||||
Value w;
|
||||
w.SetString(s, (SizeType)strlen(s), allocator);
|
||||
s[0] = '\0';
|
||||
EXPECT_STREQ("World", w.GetString());
|
||||
EXPECT_EQ(5, w.GetStringLength());
|
||||
}
|
||||
|
||||
TEST(Value, Array) {
|
||||
Value x(kArrayType);
|
||||
const Value& y = x;
|
||||
Value::AllocatorType allocator;
|
||||
|
||||
EXPECT_EQ(kArrayType, x.GetType());
|
||||
EXPECT_TRUE(x.IsArray());
|
||||
EXPECT_TRUE(x.Empty());
|
||||
EXPECT_EQ(0, x.Size());
|
||||
EXPECT_TRUE(y.IsArray());
|
||||
EXPECT_TRUE(y.Empty());
|
||||
EXPECT_EQ(0, y.Size());
|
||||
|
||||
EXPECT_FALSE(x.IsNull());
|
||||
EXPECT_FALSE(x.IsBool());
|
||||
EXPECT_FALSE(x.IsFalse());
|
||||
EXPECT_FALSE(x.IsTrue());
|
||||
EXPECT_FALSE(x.IsString());
|
||||
EXPECT_FALSE(x.IsObject());
|
||||
|
||||
// PushBack()
|
||||
Value v;
|
||||
x.PushBack(v, allocator);
|
||||
v.SetBool(true);
|
||||
x.PushBack(v, allocator);
|
||||
v.SetBool(false);
|
||||
x.PushBack(v, allocator);
|
||||
v.SetInt(123);
|
||||
x.PushBack(v, allocator);
|
||||
|
||||
EXPECT_FALSE(x.Empty());
|
||||
EXPECT_EQ(4, x.Size());
|
||||
EXPECT_FALSE(y.Empty());
|
||||
EXPECT_EQ(4, y.Size());
|
||||
EXPECT_TRUE(x[SizeType(0)].IsNull());
|
||||
EXPECT_TRUE(x[1u].IsTrue());
|
||||
EXPECT_TRUE(x[2u].IsFalse());
|
||||
EXPECT_TRUE(x[3u].IsInt());
|
||||
EXPECT_EQ(123, x[3u].GetInt());
|
||||
EXPECT_TRUE(y[SizeType(0)].IsNull());
|
||||
EXPECT_TRUE(y[1u].IsTrue());
|
||||
EXPECT_TRUE(y[2u].IsFalse());
|
||||
EXPECT_TRUE(y[3u].IsInt());
|
||||
EXPECT_EQ(123, y[3u].GetInt());
|
||||
|
||||
// iterator
|
||||
Value::ValueIterator itr = x.Begin();
|
||||
EXPECT_TRUE(itr != x.End());
|
||||
EXPECT_TRUE(itr->IsNull());
|
||||
++itr;
|
||||
EXPECT_TRUE(itr != x.End());
|
||||
EXPECT_TRUE(itr->IsTrue());
|
||||
++itr;
|
||||
EXPECT_TRUE(itr != x.End());
|
||||
EXPECT_TRUE(itr->IsFalse());
|
||||
++itr;
|
||||
EXPECT_TRUE(itr != x.End());
|
||||
EXPECT_TRUE(itr->IsInt());
|
||||
EXPECT_EQ(123, itr->GetInt());
|
||||
|
||||
// const iterator
|
||||
Value::ConstValueIterator citr = y.Begin();
|
||||
EXPECT_TRUE(citr != y.End());
|
||||
EXPECT_TRUE(citr->IsNull());
|
||||
++citr;
|
||||
EXPECT_TRUE(citr != y.End());
|
||||
EXPECT_TRUE(citr->IsTrue());
|
||||
++citr;
|
||||
EXPECT_TRUE(citr != y.End());
|
||||
EXPECT_TRUE(citr->IsFalse());
|
||||
++citr;
|
||||
EXPECT_TRUE(citr != y.End());
|
||||
EXPECT_TRUE(citr->IsInt());
|
||||
EXPECT_EQ(123, citr->GetInt());
|
||||
|
||||
// PopBack()
|
||||
x.PopBack();
|
||||
EXPECT_EQ(3, x.Size());
|
||||
EXPECT_TRUE(y[SizeType(0)].IsNull());
|
||||
EXPECT_TRUE(y[1].IsTrue());
|
||||
EXPECT_TRUE(y[2].IsFalse());
|
||||
|
||||
// Clear()
|
||||
x.Clear();
|
||||
EXPECT_TRUE(x.Empty());
|
||||
EXPECT_EQ(0, x.Size());
|
||||
EXPECT_TRUE(y.Empty());
|
||||
EXPECT_EQ(0, y.Size());
|
||||
|
||||
// SetArray()
|
||||
Value z;
|
||||
z.SetArray();
|
||||
EXPECT_TRUE(z.IsArray());
|
||||
EXPECT_TRUE(z.Empty());
|
||||
}
|
||||
|
||||
TEST(Value, Object) {
|
||||
Value x(kObjectType);
|
||||
const Value& y = x; // const version
|
||||
Value::AllocatorType allocator;
|
||||
|
||||
EXPECT_EQ(kObjectType, x.GetType());
|
||||
EXPECT_TRUE(x.IsObject());
|
||||
EXPECT_EQ(kObjectType, y.GetType());
|
||||
EXPECT_TRUE(y.IsObject());
|
||||
|
||||
// AddMember()
|
||||
Value name("A", 1);
|
||||
Value value("Apple", 5);
|
||||
x.AddMember(name, value, allocator);
|
||||
//name.SetString("B");
|
||||
name.SetString("B", 1);
|
||||
//value.SetString("Banana");
|
||||
value.SetString("Banana", 6);
|
||||
x.AddMember(name, value, allocator);
|
||||
|
||||
// HasMember()
|
||||
EXPECT_TRUE(x.HasMember("A"));
|
||||
EXPECT_TRUE(x.HasMember("B"));
|
||||
EXPECT_TRUE(y.HasMember("A"));
|
||||
EXPECT_TRUE(y.HasMember("B"));
|
||||
|
||||
// operator[]
|
||||
EXPECT_STREQ("Apple", x["A"].GetString());
|
||||
EXPECT_STREQ("Banana", x["B"].GetString());
|
||||
|
||||
// const operator[]
|
||||
EXPECT_STREQ("Apple", y["A"].GetString());
|
||||
EXPECT_STREQ("Banana", y["B"].GetString());
|
||||
|
||||
// member iterator
|
||||
Value::MemberIterator itr = x.MemberBegin();
|
||||
EXPECT_TRUE(itr != x.MemberEnd());
|
||||
EXPECT_STREQ("A", itr->name.GetString());
|
||||
EXPECT_STREQ("Apple", itr->value.GetString());
|
||||
++itr;
|
||||
EXPECT_TRUE(itr != x.MemberEnd());
|
||||
EXPECT_STREQ("B", itr->name.GetString());
|
||||
EXPECT_STREQ("Banana", itr->value.GetString());
|
||||
++itr;
|
||||
EXPECT_FALSE(itr != x.MemberEnd());
|
||||
|
||||
// const member iterator
|
||||
Value::ConstMemberIterator citr = y.MemberBegin();
|
||||
EXPECT_TRUE(citr != y.MemberEnd());
|
||||
EXPECT_STREQ("A", citr->name.GetString());
|
||||
EXPECT_STREQ("Apple", citr->value.GetString());
|
||||
++citr;
|
||||
EXPECT_TRUE(citr != y.MemberEnd());
|
||||
EXPECT_STREQ("B", citr->name.GetString());
|
||||
EXPECT_STREQ("Banana", citr->value.GetString());
|
||||
++citr;
|
||||
EXPECT_FALSE(citr != y.MemberEnd());
|
||||
|
||||
// RemoveMember()
|
||||
x.RemoveMember("A");
|
||||
EXPECT_FALSE(x.HasMember("A"));
|
||||
|
||||
x.RemoveMember("B");
|
||||
EXPECT_FALSE(x.HasMember("B"));
|
||||
|
||||
EXPECT_TRUE(x.MemberBegin() == x.MemberEnd());
|
||||
|
||||
// SetObject()
|
||||
Value z;
|
||||
z.SetObject();
|
||||
EXPECT_TRUE(z.IsObject());
|
||||
}
|
||||
|
||||
TEST(Value, BigNestedArray) {
|
||||
MemoryPoolAllocator<> allocator;
|
||||
Value x(kArrayType);
|
||||
static const SizeType n = 200;
|
||||
|
||||
for (SizeType i = 0; i < n; i++) {
|
||||
Value y(kArrayType);
|
||||
for (SizeType j = 0; j < n; j++) {
|
||||
Value number((int)(i * n + j));
|
||||
y.PushBack(number, allocator);
|
||||
}
|
||||
x.PushBack(y, allocator);
|
||||
}
|
||||
|
||||
for (SizeType i = 0; i < n; i++)
|
||||
for (SizeType j = 0; j < n; j++) {
|
||||
EXPECT_TRUE(x[i][j].IsInt());
|
||||
EXPECT_EQ((int)(i * n + j), x[i][j].GetInt());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Value, BigNestedObject) {
|
||||
MemoryPoolAllocator<> allocator;
|
||||
Value x(kObjectType);
|
||||
static const SizeType n = 200;
|
||||
|
||||
for (SizeType i = 0; i < n; i++) {
|
||||
char name1[10];
|
||||
sprintf(name1, "%d", i);
|
||||
|
||||
Value name(name1, (SizeType)strlen(name1), allocator);
|
||||
Value object(kObjectType);
|
||||
|
||||
for (SizeType j = 0; j < n; j++) {
|
||||
char name2[10];
|
||||
sprintf(name2, "%d", j);
|
||||
|
||||
Value name(name2, (SizeType)strlen(name2), allocator);
|
||||
Value number((int)(i * n + j));
|
||||
object.AddMember(name, number, allocator);
|
||||
}
|
||||
|
||||
x.AddMember(name, object, allocator);
|
||||
}
|
||||
|
||||
for (SizeType i = 0; i < n; i++) {
|
||||
char name1[10];
|
||||
sprintf(name1, "%d", i);
|
||||
|
||||
for (SizeType j = 0; j < n; j++) {
|
||||
char name2[10];
|
||||
sprintf(name2, "%d", j);
|
||||
x[name1];
|
||||
EXPECT_EQ((int)(i * n + j), x[name1][name2].GetInt());
|
||||
}
|
||||
}
|
||||
}
|
56
test/unittest/writertest.cpp
Normal file
56
test/unittest/writertest.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
#include "unittest.h"
|
||||
#include "rapidjson/reader.h"
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
TEST(Writer, Compact) {
|
||||
StringStream s("{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } ");
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
Reader reader;
|
||||
reader.Parse<0>(s, writer);
|
||||
EXPECT_STREQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3]}", buffer.GetString());
|
||||
}
|
||||
|
||||
// json -> parse -> writer -> json
|
||||
#define TEST_ROUNDTRIP(json) \
|
||||
{ \
|
||||
StringStream s(json); \
|
||||
StringBuffer buffer; \
|
||||
Writer<StringBuffer> writer(buffer); \
|
||||
Reader reader; \
|
||||
reader.Parse<0>(s, writer); \
|
||||
EXPECT_STREQ(json, buffer.GetString()); \
|
||||
}
|
||||
|
||||
TEST(Writer, Int) {
|
||||
TEST_ROUNDTRIP("[-1]");
|
||||
TEST_ROUNDTRIP("[-123]");
|
||||
TEST_ROUNDTRIP("[-2147483648]");
|
||||
}
|
||||
|
||||
TEST(Writer, UInt) {
|
||||
TEST_ROUNDTRIP("[0]");
|
||||
TEST_ROUNDTRIP("[1]");
|
||||
TEST_ROUNDTRIP("[123]");
|
||||
TEST_ROUNDTRIP("[2147483647]");
|
||||
TEST_ROUNDTRIP("[4294967295]");
|
||||
}
|
||||
|
||||
TEST(Writer, Int64) {
|
||||
TEST_ROUNDTRIP("[-1234567890123456789]");
|
||||
TEST_ROUNDTRIP("[-9223372036854775808]");
|
||||
}
|
||||
|
||||
TEST(Writer, Uint64) {
|
||||
TEST_ROUNDTRIP("[1234567890123456789]");
|
||||
TEST_ROUNDTRIP("[9223372036854775807]");
|
||||
}
|
||||
|
||||
TEST(Writer, String) {
|
||||
TEST_ROUNDTRIP("[\"Hello\"]");
|
||||
TEST_ROUNDTRIP("[\"Hello\\u0000World\"]");
|
||||
TEST_ROUNDTRIP("[\"\\\"\\\\/\\b\\f\\n\\r\\t\"]");
|
||||
}
|
130
thirdparty/gtest/CHANGES
vendored
Normal file
130
thirdparty/gtest/CHANGES
vendored
Normal file
@ -0,0 +1,130 @@
|
||||
Changes for 1.6.0:
|
||||
|
||||
* New feature: ADD_FAILURE_AT() for reporting a test failure at the
|
||||
given source location -- useful for writing testing utilities.
|
||||
* New feature: the universal value printer is moved from Google Mock
|
||||
to Google Test.
|
||||
* New feature: type parameters and value parameters are reported in
|
||||
the XML report now.
|
||||
* A gtest_disable_pthreads CMake option.
|
||||
* Colored output works in GNU Screen sessions now.
|
||||
* Parameters of value-parameterized tests are now printed in the
|
||||
textual output.
|
||||
* Failures from ad hoc test assertions run before RUN_ALL_TESTS() are
|
||||
now correctly reported.
|
||||
* Arguments of ASSERT_XY and EXPECT_XY no longer need to support << to
|
||||
ostream.
|
||||
* More complete handling of exceptions.
|
||||
* GTEST_ASSERT_XY can be used instead of ASSERT_XY in case the latter
|
||||
name is already used by another library.
|
||||
* --gtest_catch_exceptions is now true by default, allowing a test
|
||||
program to continue after an exception is thrown.
|
||||
* Value-parameterized test fixtures can now derive from Test and
|
||||
WithParamInterface<T> separately, easing conversion of legacy tests.
|
||||
* Death test messages are clearly marked to make them more
|
||||
distinguishable from other messages.
|
||||
* Compatibility fixes for Android, Google Native Client, MinGW, HP UX,
|
||||
PowerPC, Lucid autotools, libCStd, Sun C++, Borland C++ Builder (Code Gear),
|
||||
IBM XL C++ (Visual Age C++), and C++0x.
|
||||
* Bug fixes and implementation clean-ups.
|
||||
* Potentially incompatible changes: disables the harmful 'make install'
|
||||
command in autotools.
|
||||
|
||||
Changes for 1.5.0:
|
||||
|
||||
* New feature: assertions can be safely called in multiple threads
|
||||
where the pthreads library is available.
|
||||
* New feature: predicates used inside EXPECT_TRUE() and friends
|
||||
can now generate custom failure messages.
|
||||
* New feature: Google Test can now be compiled as a DLL.
|
||||
* New feature: fused source files are included.
|
||||
* New feature: prints help when encountering unrecognized Google Test flags.
|
||||
* Experimental feature: CMake build script (requires CMake 2.6.4+).
|
||||
* Experimental feature: the Pump script for meta programming.
|
||||
* double values streamed to an assertion are printed with enough precision
|
||||
to differentiate any two different values.
|
||||
* Google Test now works on Solaris and AIX.
|
||||
* Build and test script improvements.
|
||||
* Bug fixes and implementation clean-ups.
|
||||
|
||||
Potentially breaking changes:
|
||||
|
||||
* Stopped supporting VC++ 7.1 with exceptions disabled.
|
||||
* Dropped support for 'make install'.
|
||||
|
||||
Changes for 1.4.0:
|
||||
|
||||
* New feature: the event listener API
|
||||
* New feature: test shuffling
|
||||
* New feature: the XML report format is closer to junitreport and can
|
||||
be parsed by Hudson now.
|
||||
* New feature: when a test runs under Visual Studio, its failures are
|
||||
integrated in the IDE.
|
||||
* New feature: /MD(d) versions of VC++ projects.
|
||||
* New feature: elapsed time for the tests is printed by default.
|
||||
* New feature: comes with a TR1 tuple implementation such that Boost
|
||||
is no longer needed for Combine().
|
||||
* New feature: EXPECT_DEATH_IF_SUPPORTED macro and friends.
|
||||
* New feature: the Xcode project can now produce static gtest
|
||||
libraries in addition to a framework.
|
||||
* Compatibility fixes for Solaris, Cygwin, minGW, Windows Mobile,
|
||||
Symbian, gcc, and C++Builder.
|
||||
* Bug fixes and implementation clean-ups.
|
||||
|
||||
Changes for 1.3.0:
|
||||
|
||||
* New feature: death tests on Windows, Cygwin, and Mac.
|
||||
* New feature: ability to use Google Test assertions in other testing
|
||||
frameworks.
|
||||
* New feature: ability to run disabled test via
|
||||
--gtest_also_run_disabled_tests.
|
||||
* New feature: the --help flag for printing the usage.
|
||||
* New feature: access to Google Test flag values in user code.
|
||||
* New feature: a script that packs Google Test into one .h and one
|
||||
.cc file for easy deployment.
|
||||
* New feature: support for distributing test functions to multiple
|
||||
machines (requires support from the test runner).
|
||||
* Bug fixes and implementation clean-ups.
|
||||
|
||||
Changes for 1.2.1:
|
||||
|
||||
* Compatibility fixes for Linux IA-64 and IBM z/OS.
|
||||
* Added support for using Boost and other TR1 implementations.
|
||||
* Changes to the build scripts to support upcoming release of Google C++
|
||||
Mocking Framework.
|
||||
* Added Makefile to the distribution package.
|
||||
* Improved build instructions in README.
|
||||
|
||||
Changes for 1.2.0:
|
||||
|
||||
* New feature: value-parameterized tests.
|
||||
* New feature: the ASSERT/EXPECT_(NON)FATAL_FAILURE(_ON_ALL_THREADS)
|
||||
macros.
|
||||
* Changed the XML report format to match JUnit/Ant's.
|
||||
* Added tests to the Xcode project.
|
||||
* Added scons/SConscript for building with SCons.
|
||||
* Added src/gtest-all.cc for building Google Test from a single file.
|
||||
* Fixed compatibility with Solaris and z/OS.
|
||||
* Enabled running Python tests on systems with python 2.3 installed,
|
||||
e.g. Mac OS X 10.4.
|
||||
* Bug fixes.
|
||||
|
||||
Changes for 1.1.0:
|
||||
|
||||
* New feature: type-parameterized tests.
|
||||
* New feature: exception assertions.
|
||||
* New feature: printing elapsed time of tests.
|
||||
* Improved the robustness of death tests.
|
||||
* Added an Xcode project and samples.
|
||||
* Adjusted the output format on Windows to be understandable by Visual Studio.
|
||||
* Minor bug fixes.
|
||||
|
||||
Changes for 1.0.1:
|
||||
|
||||
* Added project files for Visual Studio 7.1.
|
||||
* Fixed issues with compiling on Mac OS X.
|
||||
* Fixed issues with compiling on Cygwin.
|
||||
|
||||
Changes for 1.0.0:
|
||||
|
||||
* Initial Open Source release of Google Test
|
37
thirdparty/gtest/CONTRIBUTORS
vendored
Normal file
37
thirdparty/gtest/CONTRIBUTORS
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
# This file contains a list of people who've made non-trivial
|
||||
# contribution to the Google C++ Testing Framework project. People
|
||||
# who commit code to the project are encouraged to add their names
|
||||
# here. Please keep the list sorted by first names.
|
||||
|
||||
Ajay Joshi <jaj@google.com>
|
||||
Balázs Dán <balazs.dan@gmail.com>
|
||||
Bharat Mediratta <bharat@menalto.com>
|
||||
Chandler Carruth <chandlerc@google.com>
|
||||
Chris Prince <cprince@google.com>
|
||||
Chris Taylor <taylorc@google.com>
|
||||
Dan Egnor <egnor@google.com>
|
||||
Eric Roman <eroman@chromium.org>
|
||||
Hady Zalek <hady.zalek@gmail.com>
|
||||
Jeffrey Yasskin <jyasskin@google.com>
|
||||
Jói Sigurðsson <joi@google.com>
|
||||
Keir Mierle <mierle@gmail.com>
|
||||
Keith Ray <keith.ray@gmail.com>
|
||||
Kenton Varda <kenton@google.com>
|
||||
Manuel Klimek <klimek@google.com>
|
||||
Markus Heule <markus.heule@gmail.com>
|
||||
Mika Raento <mikie@iki.fi>
|
||||
Miklós Fazekas <mfazekas@szemafor.com>
|
||||
Pasi Valminen <pasi.valminen@gmail.com>
|
||||
Patrick Hanna <phanna@google.com>
|
||||
Patrick Riley <pfr@google.com>
|
||||
Peter Kaminski <piotrk@google.com>
|
||||
Preston Jackson <preston.a.jackson@gmail.com>
|
||||
Rainer Klaffenboeck <rainer.klaffenboeck@dynatrace.com>
|
||||
Russ Cox <rsc@google.com>
|
||||
Russ Rufer <russ@pentad.com>
|
||||
Sean Mcafee <eefacm@gmail.com>
|
||||
Sigurður Ásgeirsson <siggi@google.com>
|
||||
Tracy Bialik <tracy@pentad.com>
|
||||
Vadim Berman <vadimb@google.com>
|
||||
Vlad Losev <vladl@google.com>
|
||||
Zhanyong Wan <wan@google.com>
|
28
thirdparty/gtest/COPYING
vendored
Normal file
28
thirdparty/gtest/COPYING
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
Copyright 2008, Google Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
424
thirdparty/gtest/README
vendored
Normal file
424
thirdparty/gtest/README
vendored
Normal file
@ -0,0 +1,424 @@
|
||||
Google C++ Testing Framework
|
||||
============================
|
||||
|
||||
http://code.google.com/p/googletest/
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
Google's framework for writing C++ tests on a variety of platforms
|
||||
(Linux, Mac OS X, Windows, Windows CE, Symbian, etc). Based on the
|
||||
xUnit architecture. Supports automatic test discovery, a rich set of
|
||||
assertions, user-defined assertions, death tests, fatal and non-fatal
|
||||
failures, various options for running the tests, and XML test report
|
||||
generation.
|
||||
|
||||
Please see the project page above for more information as well as the
|
||||
mailing list for questions, discussions, and development. There is
|
||||
also an IRC channel on OFTC (irc.oftc.net) #gtest available. Please
|
||||
join us!
|
||||
|
||||
Requirements for End Users
|
||||
--------------------------
|
||||
|
||||
Google Test is designed to have fairly minimal requirements to build
|
||||
and use with your projects, but there are some. Currently, we support
|
||||
Linux, Windows, Mac OS X, and Cygwin. We will also make our best
|
||||
effort to support other platforms (e.g. Solaris, AIX, and z/OS).
|
||||
However, since core members of the Google Test project have no access
|
||||
to these platforms, Google Test may have outstanding issues there. If
|
||||
you notice any problems on your platform, please notify
|
||||
googletestframework@googlegroups.com. Patches for fixing them are
|
||||
even more welcome!
|
||||
|
||||
### Linux Requirements ###
|
||||
|
||||
These are the base requirements to build and use Google Test from a source
|
||||
package (as described below):
|
||||
* GNU-compatible Make or gmake
|
||||
* POSIX-standard shell
|
||||
* POSIX(-2) Regular Expressions (regex.h)
|
||||
* A C++98-standard-compliant compiler
|
||||
|
||||
### Windows Requirements ###
|
||||
|
||||
* Microsoft Visual C++ 7.1 or newer
|
||||
|
||||
### Cygwin Requirements ###
|
||||
|
||||
* Cygwin 1.5.25-14 or newer
|
||||
|
||||
### Mac OS X Requirements ###
|
||||
|
||||
* Mac OS X 10.4 Tiger or newer
|
||||
* Developer Tools Installed
|
||||
|
||||
Also, you'll need CMake 2.6.4 or higher if you want to build the
|
||||
samples using the provided CMake script, regardless of the platform.
|
||||
|
||||
Requirements for Contributors
|
||||
-----------------------------
|
||||
|
||||
We welcome patches. If you plan to contribute a patch, you need to
|
||||
build Google Test and its own tests from an SVN checkout (described
|
||||
below), which has further requirements:
|
||||
|
||||
* Python version 2.3 or newer (for running some of the tests and
|
||||
re-generating certain source files from templates)
|
||||
* CMake 2.6.4 or newer
|
||||
|
||||
Getting the Source
|
||||
------------------
|
||||
|
||||
There are two primary ways of getting Google Test's source code: you
|
||||
can download a stable source release in your preferred archive format,
|
||||
or directly check out the source from our Subversion (SVN) repositary.
|
||||
The SVN checkout requires a few extra steps and some extra software
|
||||
packages on your system, but lets you track the latest development and
|
||||
make patches much more easily, so we highly encourage it.
|
||||
|
||||
### Source Package ###
|
||||
|
||||
Google Test is released in versioned source packages which can be
|
||||
downloaded from the download page [1]. Several different archive
|
||||
formats are provided, but the only difference is the tools used to
|
||||
manipulate them, and the size of the resulting file. Download
|
||||
whichever you are most comfortable with.
|
||||
|
||||
[1] http://code.google.com/p/googletest/downloads/list
|
||||
|
||||
Once the package is downloaded, expand it using whichever tools you
|
||||
prefer for that type. This will result in a new directory with the
|
||||
name "gtest-X.Y.Z" which contains all of the source code. Here are
|
||||
some examples on Linux:
|
||||
|
||||
tar -xvzf gtest-X.Y.Z.tar.gz
|
||||
tar -xvjf gtest-X.Y.Z.tar.bz2
|
||||
unzip gtest-X.Y.Z.zip
|
||||
|
||||
### SVN Checkout ###
|
||||
|
||||
To check out the main branch (also known as the "trunk") of Google
|
||||
Test, run the following Subversion command:
|
||||
|
||||
svn checkout http://googletest.googlecode.com/svn/trunk/ gtest-svn
|
||||
|
||||
Setting up the Build
|
||||
--------------------
|
||||
|
||||
To build Google Test and your tests that use it, you need to tell your
|
||||
build system where to find its headers and source files. The exact
|
||||
way to do it depends on which build system you use, and is usually
|
||||
straightforward.
|
||||
|
||||
### Generic Build Instructions ###
|
||||
|
||||
Suppose you put Google Test in directory ${GTEST_DIR}. To build it,
|
||||
create a library build target (or a project as called by Visual Studio
|
||||
and Xcode) to compile
|
||||
|
||||
${GTEST_DIR}/src/gtest-all.cc
|
||||
|
||||
with
|
||||
|
||||
${GTEST_DIR}/include and ${GTEST_DIR}
|
||||
|
||||
in the header search path. Assuming a Linux-like system and gcc,
|
||||
something like the following will do:
|
||||
|
||||
g++ -I${GTEST_DIR}/include -I${GTEST_DIR} -c ${GTEST_DIR}/src/gtest-all.cc
|
||||
ar -rv libgtest.a gtest-all.o
|
||||
|
||||
Next, you should compile your test source file with
|
||||
${GTEST_DIR}/include in the header search path, and link it with gtest
|
||||
and any other necessary libraries:
|
||||
|
||||
g++ -I${GTEST_DIR}/include path/to/your_test.cc libgtest.a -o your_test
|
||||
|
||||
As an example, the make/ directory contains a Makefile that you can
|
||||
use to build Google Test on systems where GNU make is available
|
||||
(e.g. Linux, Mac OS X, and Cygwin). It doesn't try to build Google
|
||||
Test's own tests. Instead, it just builds the Google Test library and
|
||||
a sample test. You can use it as a starting point for your own build
|
||||
script.
|
||||
|
||||
If the default settings are correct for your environment, the
|
||||
following commands should succeed:
|
||||
|
||||
cd ${GTEST_DIR}/make
|
||||
make
|
||||
./sample1_unittest
|
||||
|
||||
If you see errors, try to tweak the contents of make/Makefile to make
|
||||
them go away. There are instructions in make/Makefile on how to do
|
||||
it.
|
||||
|
||||
### Using CMake ###
|
||||
|
||||
Google Test comes with a CMake build script (CMakeLists.txt) that can
|
||||
be used on a wide range of platforms ("C" stands for cross-platofrm.).
|
||||
If you don't have CMake installed already, you can download it for
|
||||
free from http://www.cmake.org/.
|
||||
|
||||
CMake works by generating native makefiles or build projects that can
|
||||
be used in the compiler environment of your choice. The typical
|
||||
workflow starts with:
|
||||
|
||||
mkdir mybuild # Create a directory to hold the build output.
|
||||
cd mybuild
|
||||
cmake ${GTEST_DIR} # Generate native build scripts.
|
||||
|
||||
If you want to build Google Test's samples, you should replace the
|
||||
last command with
|
||||
|
||||
cmake -Dgtest_build_samples=ON ${GTEST_DIR}
|
||||
|
||||
If you are on a *nix system, you should now see a Makefile in the
|
||||
current directory. Just type 'make' to build gtest.
|
||||
|
||||
If you use Windows and have Vistual Studio installed, a gtest.sln file
|
||||
and several .vcproj files will be created. You can then build them
|
||||
using Visual Studio.
|
||||
|
||||
On Mac OS X with Xcode installed, a .xcodeproj file will be generated.
|
||||
|
||||
### Legacy Build Scripts ###
|
||||
|
||||
Before settling on CMake, we have been providing hand-maintained build
|
||||
projects/scripts for Visual Studio, Xcode, and Autotools. While we
|
||||
continue to provide them for convenience, they are not actively
|
||||
maintained any more. We highly recommend that you follow the
|
||||
instructions in the previous two sections to integrate Google Test
|
||||
with your existing build system.
|
||||
|
||||
If you still need to use the legacy build scripts, here's how:
|
||||
|
||||
The msvc\ folder contains two solutions with Visual C++ projects.
|
||||
Open the gtest.sln or gtest-md.sln file using Visual Studio, and you
|
||||
are ready to build Google Test the same way you build any Visual
|
||||
Studio project. Files that have names ending with -md use DLL
|
||||
versions of Microsoft runtime libraries (the /MD or the /MDd compiler
|
||||
option). Files without that suffix use static versions of the runtime
|
||||
libraries (the /MT or the /MTd option). Please note that one must use
|
||||
the same option to compile both gtest and the test code. If you use
|
||||
Visual Studio 2005 or above, we recommend the -md version as /MD is
|
||||
the default for new projects in these versions of Visual Studio.
|
||||
|
||||
On Mac OS X, open the gtest.xcodeproj in the xcode/ folder using
|
||||
Xcode. Build the "gtest" target. The universal binary framework will
|
||||
end up in your selected build directory (selected in the Xcode
|
||||
"Preferences..." -> "Building" pane and defaults to xcode/build).
|
||||
Alternatively, at the command line, enter:
|
||||
|
||||
xcodebuild
|
||||
|
||||
This will build the "Release" configuration of gtest.framework in your
|
||||
default build location. See the "xcodebuild" man page for more
|
||||
information about building different configurations and building in
|
||||
different locations.
|
||||
|
||||
Tweaking Google Test
|
||||
--------------------
|
||||
|
||||
Google Test can be used in diverse environments. The default
|
||||
configuration may not work (or may not work well) out of the box in
|
||||
some environments. However, you can easily tweak Google Test by
|
||||
defining control macros on the compiler command line. Generally,
|
||||
these macros are named like GTEST_XYZ and you define them to either 1
|
||||
or 0 to enable or disable a certain feature.
|
||||
|
||||
We list the most frequently used macros below. For a complete list,
|
||||
see file include/gtest/internal/gtest-port.h.
|
||||
|
||||
### Choosing a TR1 Tuple Library ###
|
||||
|
||||
Some Google Test features require the C++ Technical Report 1 (TR1)
|
||||
tuple library, which is not yet available with all compilers. The
|
||||
good news is that Google Test implements a subset of TR1 tuple that's
|
||||
enough for its own need, and will automatically use this when the
|
||||
compiler doesn't provide TR1 tuple.
|
||||
|
||||
Usually you don't need to care about which tuple library Google Test
|
||||
uses. However, if your project already uses TR1 tuple, you need to
|
||||
tell Google Test to use the same TR1 tuple library the rest of your
|
||||
project uses, or the two tuple implementations will clash. To do
|
||||
that, add
|
||||
|
||||
-DGTEST_USE_OWN_TR1_TUPLE=0
|
||||
|
||||
to the compiler flags while compiling Google Test and your tests. If
|
||||
you want to force Google Test to use its own tuple library, just add
|
||||
|
||||
-DGTEST_USE_OWN_TR1_TUPLE=1
|
||||
|
||||
to the compiler flags instead.
|
||||
|
||||
If you don't want Google Test to use tuple at all, add
|
||||
|
||||
-DGTEST_HAS_TR1_TUPLE=0
|
||||
|
||||
and all features using tuple will be disabled.
|
||||
|
||||
### Multi-threaded Tests ###
|
||||
|
||||
Google Test is thread-safe where the pthread library is available.
|
||||
After #include "gtest/gtest.h", you can check the GTEST_IS_THREADSAFE
|
||||
macro to see whether this is the case (yes if the macro is #defined to
|
||||
1, no if it's undefined.).
|
||||
|
||||
If Google Test doesn't correctly detect whether pthread is available
|
||||
in your environment, you can force it with
|
||||
|
||||
-DGTEST_HAS_PTHREAD=1
|
||||
|
||||
or
|
||||
|
||||
-DGTEST_HAS_PTHREAD=0
|
||||
|
||||
When Google Test uses pthread, you may need to add flags to your
|
||||
compiler and/or linker to select the pthread library, or you'll get
|
||||
link errors. If you use the CMake script or the deprecated Autotools
|
||||
script, this is taken care of for you. If you use your own build
|
||||
script, you'll need to read your compiler and linker's manual to
|
||||
figure out what flags to add.
|
||||
|
||||
### As a Shared Library (DLL) ###
|
||||
|
||||
Google Test is compact, so most users can build and link it as a
|
||||
static library for the simplicity. You can choose to use Google Test
|
||||
as a shared library (known as a DLL on Windows) if you prefer.
|
||||
|
||||
To compile *gtest* as a shared library, add
|
||||
|
||||
-DGTEST_CREATE_SHARED_LIBRARY=1
|
||||
|
||||
to the compiler flags. You'll also need to tell the linker to produce
|
||||
a shared library instead - consult your linker's manual for how to do
|
||||
it.
|
||||
|
||||
To compile your *tests* that use the gtest shared library, add
|
||||
|
||||
-DGTEST_LINKED_AS_SHARED_LIBRARY=1
|
||||
|
||||
to the compiler flags.
|
||||
|
||||
Note: while the above steps aren't technically necessary today when
|
||||
using some compilers (e.g. GCC), they may become necessary in the
|
||||
future, if we decide to improve the speed of loading the library (see
|
||||
http://gcc.gnu.org/wiki/Visibility for details). Therefore you are
|
||||
recommended to always add the above flags when using Google Test as a
|
||||
shared library. Otherwise a future release of Google Test may break
|
||||
your build script.
|
||||
|
||||
### Avoiding Macro Name Clashes ###
|
||||
|
||||
In C++, macros don't obey namespaces. Therefore two libraries that
|
||||
both define a macro of the same name will clash if you #include both
|
||||
definitions. In case a Google Test macro clashes with another
|
||||
library, you can force Google Test to rename its macro to avoid the
|
||||
conflict.
|
||||
|
||||
Specifically, if both Google Test and some other code define macro
|
||||
FOO, you can add
|
||||
|
||||
-DGTEST_DONT_DEFINE_FOO=1
|
||||
|
||||
to the compiler flags to tell Google Test to change the macro's name
|
||||
from FOO to GTEST_FOO. Currently FOO can be FAIL, SUCCEED, or TEST.
|
||||
For example, with -DGTEST_DONT_DEFINE_TEST=1, you'll need to write
|
||||
|
||||
GTEST_TEST(SomeTest, DoesThis) { ... }
|
||||
|
||||
instead of
|
||||
|
||||
TEST(SomeTest, DoesThis) { ... }
|
||||
|
||||
in order to define a test.
|
||||
|
||||
Upgrating from an Earlier Version
|
||||
---------------------------------
|
||||
|
||||
We strive to keep Google Test releases backward compatible.
|
||||
Sometimes, though, we have to make some breaking changes for the
|
||||
users' long-term benefits. This section describes what you'll need to
|
||||
do if you are upgrading from an earlier version of Google Test.
|
||||
|
||||
### Upgrading from 1.3.0 or Earlier ###
|
||||
|
||||
You may need to explicitly enable or disable Google Test's own TR1
|
||||
tuple library. See the instructions in section "Choosing a TR1 Tuple
|
||||
Library".
|
||||
|
||||
### Upgrading from 1.4.0 or Earlier ###
|
||||
|
||||
The Autotools build script (configure + make) is no longer officially
|
||||
supportted. You are encouraged to migrate to your own build system or
|
||||
use CMake. If you still need to use Autotools, you can find
|
||||
instructions in the README file from Google Test 1.4.0.
|
||||
|
||||
On platforms where the pthread library is available, Google Test uses
|
||||
it in order to be thread-safe. See the "Multi-threaded Tests" section
|
||||
for what this means to your build script.
|
||||
|
||||
If you use Microsoft Visual C++ 7.1 with exceptions disabled, Google
|
||||
Test will no longer compile. This should affect very few people, as a
|
||||
large portion of STL (including <string>) doesn't compile in this mode
|
||||
anyway. We decided to stop supporting it in order to greatly simplify
|
||||
Google Test's implementation.
|
||||
|
||||
Developing Google Test
|
||||
----------------------
|
||||
|
||||
This section discusses how to make your own changes to Google Test.
|
||||
|
||||
### Testing Google Test Itself ###
|
||||
|
||||
To make sure your changes work as intended and don't break existing
|
||||
functionality, you'll want to compile and run Google Test's own tests.
|
||||
For that you can use CMake:
|
||||
|
||||
mkdir mybuild
|
||||
cd mybuild
|
||||
cmake -Dgtest_build_tests=ON ${GTEST_DIR}
|
||||
|
||||
Make sure you have Python installed, as some of Google Test's tests
|
||||
are written in Python. If the cmake command complains about not being
|
||||
able to find Python ("Could NOT find PythonInterp (missing:
|
||||
PYTHON_EXECUTABLE)"), try telling it explicitly where your Python
|
||||
executable can be found:
|
||||
|
||||
cmake -DPYTHON_EXECUTABLE=path/to/python -Dgtest_build_tests=ON ${GTEST_DIR}
|
||||
|
||||
Next, you can build Google Test and all of its own tests. On *nix,
|
||||
this is usually done by 'make'. To run the tests, do
|
||||
|
||||
make test
|
||||
|
||||
All tests should pass.
|
||||
|
||||
### Regenerating Source Files ###
|
||||
|
||||
Some of Google Test's source files are generated from templates (not
|
||||
in the C++ sense) using a script. A template file is named FOO.pump,
|
||||
where FOO is the name of the file it will generate. For example, the
|
||||
file include/gtest/internal/gtest-type-util.h.pump is used to generate
|
||||
gtest-type-util.h in the same directory.
|
||||
|
||||
Normally you don't need to worry about regenerating the source files,
|
||||
unless you need to modify them. In that case, you should modify the
|
||||
corresponding .pump files instead and run the pump.py Python script to
|
||||
regenerate them. You can find pump.py in the scripts/ directory.
|
||||
Read the Pump manual [2] for how to use it.
|
||||
|
||||
[2] http://code.google.com/p/googletest/wiki/PumpManual
|
||||
|
||||
### Contributing a Patch ###
|
||||
|
||||
We welcome patches. Please read the Google Test developer's guide [3]
|
||||
for how you can contribute. In particular, make sure you have signed
|
||||
the Contributor License Agreement, or we won't be able to accept the
|
||||
patch.
|
||||
|
||||
[3] http://code.google.com/p/googletest/wiki/GoogleTestDevGuide
|
||||
|
||||
Happy testing!
|
283
thirdparty/gtest/include/gtest/gtest-death-test.h
vendored
Normal file
283
thirdparty/gtest/include/gtest/gtest-death-test.h
vendored
Normal file
@ -0,0 +1,283 @@
|
||||
// Copyright 2005, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
//
|
||||
// The Google C++ Testing Framework (Google Test)
|
||||
//
|
||||
// This header file defines the public API for death tests. It is
|
||||
// #included by gtest.h so a user doesn't need to include this
|
||||
// directly.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
|
||||
|
||||
#include "gtest/internal/gtest-death-test-internal.h"
|
||||
|
||||
namespace testing {
|
||||
|
||||
// This flag controls the style of death tests. Valid values are "threadsafe",
|
||||
// meaning that the death test child process will re-execute the test binary
|
||||
// from the start, running only a single death test, or "fast",
|
||||
// meaning that the child process will execute the test logic immediately
|
||||
// after forking.
|
||||
GTEST_DECLARE_string_(death_test_style);
|
||||
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
|
||||
// The following macros are useful for writing death tests.
|
||||
|
||||
// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is
|
||||
// executed:
|
||||
//
|
||||
// 1. It generates a warning if there is more than one active
|
||||
// thread. This is because it's safe to fork() or clone() only
|
||||
// when there is a single thread.
|
||||
//
|
||||
// 2. The parent process clone()s a sub-process and runs the death
|
||||
// test in it; the sub-process exits with code 0 at the end of the
|
||||
// death test, if it hasn't exited already.
|
||||
//
|
||||
// 3. The parent process waits for the sub-process to terminate.
|
||||
//
|
||||
// 4. The parent process checks the exit code and error message of
|
||||
// the sub-process.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number");
|
||||
// for (int i = 0; i < 5; i++) {
|
||||
// EXPECT_DEATH(server.ProcessRequest(i),
|
||||
// "Invalid request .* in ProcessRequest()")
|
||||
// << "Failed to die on request " << i);
|
||||
// }
|
||||
//
|
||||
// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting");
|
||||
//
|
||||
// bool KilledBySIGHUP(int exit_code) {
|
||||
// return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP;
|
||||
// }
|
||||
//
|
||||
// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!");
|
||||
//
|
||||
// On the regular expressions used in death tests:
|
||||
//
|
||||
// On POSIX-compliant systems (*nix), we use the <regex.h> library,
|
||||
// which uses the POSIX extended regex syntax.
|
||||
//
|
||||
// On other platforms (e.g. Windows), we only support a simple regex
|
||||
// syntax implemented as part of Google Test. This limited
|
||||
// implementation should be enough most of the time when writing
|
||||
// death tests; though it lacks many features you can find in PCRE
|
||||
// or POSIX extended regex syntax. For example, we don't support
|
||||
// union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and
|
||||
// repetition count ("x{5,7}"), among others.
|
||||
//
|
||||
// Below is the syntax that we do support. We chose it to be a
|
||||
// subset of both PCRE and POSIX extended regex, so it's easy to
|
||||
// learn wherever you come from. In the following: 'A' denotes a
|
||||
// literal character, period (.), or a single \\ escape sequence;
|
||||
// 'x' and 'y' denote regular expressions; 'm' and 'n' are for
|
||||
// natural numbers.
|
||||
//
|
||||
// c matches any literal character c
|
||||
// \\d matches any decimal digit
|
||||
// \\D matches any character that's not a decimal digit
|
||||
// \\f matches \f
|
||||
// \\n matches \n
|
||||
// \\r matches \r
|
||||
// \\s matches any ASCII whitespace, including \n
|
||||
// \\S matches any character that's not a whitespace
|
||||
// \\t matches \t
|
||||
// \\v matches \v
|
||||
// \\w matches any letter, _, or decimal digit
|
||||
// \\W matches any character that \\w doesn't match
|
||||
// \\c matches any literal character c, which must be a punctuation
|
||||
// . matches any single character except \n
|
||||
// A? matches 0 or 1 occurrences of A
|
||||
// A* matches 0 or many occurrences of A
|
||||
// A+ matches 1 or many occurrences of A
|
||||
// ^ matches the beginning of a string (not that of each line)
|
||||
// $ matches the end of a string (not that of each line)
|
||||
// xy matches x followed by y
|
||||
//
|
||||
// If you accidentally use PCRE or POSIX extended regex features
|
||||
// not implemented by us, you will get a run-time failure. In that
|
||||
// case, please try to rewrite your regular expression within the
|
||||
// above syntax.
|
||||
//
|
||||
// This implementation is *not* meant to be as highly tuned or robust
|
||||
// as a compiled regex library, but should perform well enough for a
|
||||
// death test, which already incurs significant overhead by launching
|
||||
// a child process.
|
||||
//
|
||||
// Known caveats:
|
||||
//
|
||||
// A "threadsafe" style death test obtains the path to the test
|
||||
// program from argv[0] and re-executes it in the sub-process. For
|
||||
// simplicity, the current implementation doesn't search the PATH
|
||||
// when launching the sub-process. This means that the user must
|
||||
// invoke the test program via a path that contains at least one
|
||||
// path separator (e.g. path/to/foo_test and
|
||||
// /absolute/path/to/bar_test are fine, but foo_test is not). This
|
||||
// is rarely a problem as people usually don't put the test binary
|
||||
// directory in PATH.
|
||||
//
|
||||
// TODO(wan@google.com): make thread-safe death tests search the PATH.
|
||||
|
||||
// Asserts that a given statement causes the program to exit, with an
|
||||
// integer exit status that satisfies predicate, and emitting error output
|
||||
// that matches regex.
|
||||
# define ASSERT_EXIT(statement, predicate, regex) \
|
||||
GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_)
|
||||
|
||||
// Like ASSERT_EXIT, but continues on to successive tests in the
|
||||
// test case, if any:
|
||||
# define EXPECT_EXIT(statement, predicate, regex) \
|
||||
GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_)
|
||||
|
||||
// Asserts that a given statement causes the program to exit, either by
|
||||
// explicitly exiting with a nonzero exit code or being killed by a
|
||||
// signal, and emitting error output that matches regex.
|
||||
# define ASSERT_DEATH(statement, regex) \
|
||||
ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
|
||||
|
||||
// Like ASSERT_DEATH, but continues on to successive tests in the
|
||||
// test case, if any:
|
||||
# define EXPECT_DEATH(statement, regex) \
|
||||
EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
|
||||
|
||||
// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*:
|
||||
|
||||
// Tests that an exit code describes a normal exit with a given exit code.
|
||||
class GTEST_API_ ExitedWithCode {
|
||||
public:
|
||||
explicit ExitedWithCode(int exit_code);
|
||||
bool operator()(int exit_status) const;
|
||||
private:
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const ExitedWithCode& other);
|
||||
|
||||
const int exit_code_;
|
||||
};
|
||||
|
||||
# if !GTEST_OS_WINDOWS
|
||||
// Tests that an exit code describes an exit due to termination by a
|
||||
// given signal.
|
||||
class GTEST_API_ KilledBySignal {
|
||||
public:
|
||||
explicit KilledBySignal(int signum);
|
||||
bool operator()(int exit_status) const;
|
||||
private:
|
||||
const int signum_;
|
||||
};
|
||||
# endif // !GTEST_OS_WINDOWS
|
||||
|
||||
// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode.
|
||||
// The death testing framework causes this to have interesting semantics,
|
||||
// since the sideeffects of the call are only visible in opt mode, and not
|
||||
// in debug mode.
|
||||
//
|
||||
// In practice, this can be used to test functions that utilize the
|
||||
// LOG(DFATAL) macro using the following style:
|
||||
//
|
||||
// int DieInDebugOr12(int* sideeffect) {
|
||||
// if (sideeffect) {
|
||||
// *sideeffect = 12;
|
||||
// }
|
||||
// LOG(DFATAL) << "death";
|
||||
// return 12;
|
||||
// }
|
||||
//
|
||||
// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) {
|
||||
// int sideeffect = 0;
|
||||
// // Only asserts in dbg.
|
||||
// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death");
|
||||
//
|
||||
// #ifdef NDEBUG
|
||||
// // opt-mode has sideeffect visible.
|
||||
// EXPECT_EQ(12, sideeffect);
|
||||
// #else
|
||||
// // dbg-mode no visible sideeffect.
|
||||
// EXPECT_EQ(0, sideeffect);
|
||||
// #endif
|
||||
// }
|
||||
//
|
||||
// This will assert that DieInDebugReturn12InOpt() crashes in debug
|
||||
// mode, usually due to a DCHECK or LOG(DFATAL), but returns the
|
||||
// appropriate fallback value (12 in this case) in opt mode. If you
|
||||
// need to test that a function has appropriate side-effects in opt
|
||||
// mode, include assertions against the side-effects. A general
|
||||
// pattern for this is:
|
||||
//
|
||||
// EXPECT_DEBUG_DEATH({
|
||||
// // Side-effects here will have an effect after this statement in
|
||||
// // opt mode, but none in debug mode.
|
||||
// EXPECT_EQ(12, DieInDebugOr12(&sideeffect));
|
||||
// }, "death");
|
||||
//
|
||||
# ifdef NDEBUG
|
||||
|
||||
# define EXPECT_DEBUG_DEATH(statement, regex) \
|
||||
do { statement; } while (::testing::internal::AlwaysFalse())
|
||||
|
||||
# define ASSERT_DEBUG_DEATH(statement, regex) \
|
||||
do { statement; } while (::testing::internal::AlwaysFalse())
|
||||
|
||||
# else
|
||||
|
||||
# define EXPECT_DEBUG_DEATH(statement, regex) \
|
||||
EXPECT_DEATH(statement, regex)
|
||||
|
||||
# define ASSERT_DEBUG_DEATH(statement, regex) \
|
||||
ASSERT_DEATH(statement, regex)
|
||||
|
||||
# endif // NDEBUG for EXPECT_DEBUG_DEATH
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
|
||||
// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and
|
||||
// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if
|
||||
// death tests are supported; otherwise they just issue a warning. This is
|
||||
// useful when you are combining death test assertions with normal test
|
||||
// assertions in one test.
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
|
||||
EXPECT_DEATH(statement, regex)
|
||||
# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
|
||||
ASSERT_DEATH(statement, regex)
|
||||
#else
|
||||
# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
|
||||
GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, )
|
||||
# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
|
||||
GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return)
|
||||
#endif
|
||||
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
|
230
thirdparty/gtest/include/gtest/gtest-message.h
vendored
Normal file
230
thirdparty/gtest/include/gtest/gtest-message.h
vendored
Normal file
@ -0,0 +1,230 @@
|
||||
// Copyright 2005, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
//
|
||||
// The Google C++ Testing Framework (Google Test)
|
||||
//
|
||||
// This header file defines the Message class.
|
||||
//
|
||||
// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
|
||||
// leave some internal implementation details in this header file.
|
||||
// They are clearly marked by comments like this:
|
||||
//
|
||||
// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
|
||||
//
|
||||
// Such code is NOT meant to be used by a user directly, and is subject
|
||||
// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user
|
||||
// program!
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "gtest/internal/gtest-string.h"
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
|
||||
namespace testing {
|
||||
|
||||
// The Message class works like an ostream repeater.
|
||||
//
|
||||
// Typical usage:
|
||||
//
|
||||
// 1. You stream a bunch of values to a Message object.
|
||||
// It will remember the text in a stringstream.
|
||||
// 2. Then you stream the Message object to an ostream.
|
||||
// This causes the text in the Message to be streamed
|
||||
// to the ostream.
|
||||
//
|
||||
// For example;
|
||||
//
|
||||
// testing::Message foo;
|
||||
// foo << 1 << " != " << 2;
|
||||
// std::cout << foo;
|
||||
//
|
||||
// will print "1 != 2".
|
||||
//
|
||||
// Message is not intended to be inherited from. In particular, its
|
||||
// destructor is not virtual.
|
||||
//
|
||||
// Note that stringstream behaves differently in gcc and in MSVC. You
|
||||
// can stream a NULL char pointer to it in the former, but not in the
|
||||
// latter (it causes an access violation if you do). The Message
|
||||
// class hides this difference by treating a NULL char pointer as
|
||||
// "(null)".
|
||||
class GTEST_API_ Message {
|
||||
private:
|
||||
// The type of basic IO manipulators (endl, ends, and flush) for
|
||||
// narrow streams.
|
||||
typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&);
|
||||
|
||||
public:
|
||||
// Constructs an empty Message.
|
||||
// We allocate the stringstream separately because otherwise each use of
|
||||
// ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's
|
||||
// stack frame leading to huge stack frames in some cases; gcc does not reuse
|
||||
// the stack space.
|
||||
Message() : ss_(new ::std::stringstream) {
|
||||
// By default, we want there to be enough precision when printing
|
||||
// a double to a Message.
|
||||
*ss_ << std::setprecision(std::numeric_limits<double>::digits10 + 2);
|
||||
}
|
||||
|
||||
// Copy constructor.
|
||||
Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT
|
||||
*ss_ << msg.GetString();
|
||||
}
|
||||
|
||||
// Constructs a Message from a C-string.
|
||||
explicit Message(const char* str) : ss_(new ::std::stringstream) {
|
||||
*ss_ << str;
|
||||
}
|
||||
|
||||
#if GTEST_OS_SYMBIAN
|
||||
// Streams a value (either a pointer or not) to this object.
|
||||
template <typename T>
|
||||
inline Message& operator <<(const T& value) {
|
||||
StreamHelper(typename internal::is_pointer<T>::type(), value);
|
||||
return *this;
|
||||
}
|
||||
#else
|
||||
// Streams a non-pointer value to this object.
|
||||
template <typename T>
|
||||
inline Message& operator <<(const T& val) {
|
||||
::GTestStreamToHelper(ss_.get(), val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Streams a pointer value to this object.
|
||||
//
|
||||
// This function is an overload of the previous one. When you
|
||||
// stream a pointer to a Message, this definition will be used as it
|
||||
// is more specialized. (The C++ Standard, section
|
||||
// [temp.func.order].) If you stream a non-pointer, then the
|
||||
// previous definition will be used.
|
||||
//
|
||||
// The reason for this overload is that streaming a NULL pointer to
|
||||
// ostream is undefined behavior. Depending on the compiler, you
|
||||
// may get "0", "(nil)", "(null)", or an access violation. To
|
||||
// ensure consistent result across compilers, we always treat NULL
|
||||
// as "(null)".
|
||||
template <typename T>
|
||||
inline Message& operator <<(T* const& pointer) { // NOLINT
|
||||
if (pointer == NULL) {
|
||||
*ss_ << "(null)";
|
||||
} else {
|
||||
::GTestStreamToHelper(ss_.get(), pointer);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
#endif // GTEST_OS_SYMBIAN
|
||||
|
||||
// Since the basic IO manipulators are overloaded for both narrow
|
||||
// and wide streams, we have to provide this specialized definition
|
||||
// of operator <<, even though its body is the same as the
|
||||
// templatized version above. Without this definition, streaming
|
||||
// endl or other basic IO manipulators to Message will confuse the
|
||||
// compiler.
|
||||
Message& operator <<(BasicNarrowIoManip val) {
|
||||
*ss_ << val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Instead of 1/0, we want to see true/false for bool values.
|
||||
Message& operator <<(bool b) {
|
||||
return *this << (b ? "true" : "false");
|
||||
}
|
||||
|
||||
// These two overloads allow streaming a wide C string to a Message
|
||||
// using the UTF-8 encoding.
|
||||
Message& operator <<(const wchar_t* wide_c_str) {
|
||||
return *this << internal::String::ShowWideCString(wide_c_str);
|
||||
}
|
||||
Message& operator <<(wchar_t* wide_c_str) {
|
||||
return *this << internal::String::ShowWideCString(wide_c_str);
|
||||
}
|
||||
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
// Converts the given wide string to a narrow string using the UTF-8
|
||||
// encoding, and streams the result to this Message object.
|
||||
Message& operator <<(const ::std::wstring& wstr);
|
||||
#endif // GTEST_HAS_STD_WSTRING
|
||||
|
||||
#if GTEST_HAS_GLOBAL_WSTRING
|
||||
// Converts the given wide string to a narrow string using the UTF-8
|
||||
// encoding, and streams the result to this Message object.
|
||||
Message& operator <<(const ::wstring& wstr);
|
||||
#endif // GTEST_HAS_GLOBAL_WSTRING
|
||||
|
||||
// Gets the text streamed to this object so far as a String.
|
||||
// Each '\0' character in the buffer is replaced with "\\0".
|
||||
//
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
|
||||
internal::String GetString() const {
|
||||
return internal::StringStreamToString(ss_.get());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
#if GTEST_OS_SYMBIAN
|
||||
// These are needed as the Nokia Symbian Compiler cannot decide between
|
||||
// const T& and const T* in a function template. The Nokia compiler _can_
|
||||
// decide between class template specializations for T and T*, so a
|
||||
// tr1::type_traits-like is_pointer works, and we can overload on that.
|
||||
template <typename T>
|
||||
inline void StreamHelper(internal::true_type /*dummy*/, T* pointer) {
|
||||
if (pointer == NULL) {
|
||||
*ss_ << "(null)";
|
||||
} else {
|
||||
::GTestStreamToHelper(ss_.get(), pointer);
|
||||
}
|
||||
}
|
||||
template <typename T>
|
||||
inline void StreamHelper(internal::false_type /*dummy*/, const T& value) {
|
||||
::GTestStreamToHelper(ss_.get(), value);
|
||||
}
|
||||
#endif // GTEST_OS_SYMBIAN
|
||||
|
||||
// We'll hold the text streamed to this object here.
|
||||
const internal::scoped_ptr< ::std::stringstream> ss_;
|
||||
|
||||
// We declare (but don't implement) this to prevent the compiler
|
||||
// from implementing the assignment operator.
|
||||
void operator=(const Message&);
|
||||
};
|
||||
|
||||
// Streams a Message to an ostream.
|
||||
inline std::ostream& operator <<(std::ostream& os, const Message& sb) {
|
||||
return os << sb.GetString();
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
|
1421
thirdparty/gtest/include/gtest/gtest-param-test.h
vendored
Normal file
1421
thirdparty/gtest/include/gtest/gtest-param-test.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
487
thirdparty/gtest/include/gtest/gtest-param-test.h.pump
vendored
Normal file
487
thirdparty/gtest/include/gtest/gtest-param-test.h.pump
vendored
Normal file
@ -0,0 +1,487 @@
|
||||
$$ -*- mode: c++; -*-
|
||||
$var n = 50 $$ Maximum length of Values arguments we want to support.
|
||||
$var maxtuple = 10 $$ Maximum number of Combine arguments we want to support.
|
||||
// Copyright 2008, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Authors: vladl@google.com (Vlad Losev)
|
||||
//
|
||||
// Macros and functions for implementing parameterized tests
|
||||
// in Google C++ Testing Framework (Google Test)
|
||||
//
|
||||
// This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
|
||||
//
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
|
||||
|
||||
|
||||
// Value-parameterized tests allow you to test your code with different
|
||||
// parameters without writing multiple copies of the same test.
|
||||
//
|
||||
// Here is how you use value-parameterized tests:
|
||||
|
||||
#if 0
|
||||
|
||||
// To write value-parameterized tests, first you should define a fixture
|
||||
// class. It is usually derived from testing::TestWithParam<T> (see below for
|
||||
// another inheritance scheme that's sometimes useful in more complicated
|
||||
// class hierarchies), where the type of your parameter values.
|
||||
// TestWithParam<T> is itself derived from testing::Test. T can be any
|
||||
// copyable type. If it's a raw pointer, you are responsible for managing the
|
||||
// lifespan of the pointed values.
|
||||
|
||||
class FooTest : public ::testing::TestWithParam<const char*> {
|
||||
// You can implement all the usual class fixture members here.
|
||||
};
|
||||
|
||||
// Then, use the TEST_P macro to define as many parameterized tests
|
||||
// for this fixture as you want. The _P suffix is for "parameterized"
|
||||
// or "pattern", whichever you prefer to think.
|
||||
|
||||
TEST_P(FooTest, DoesBlah) {
|
||||
// Inside a test, access the test parameter with the GetParam() method
|
||||
// of the TestWithParam<T> class:
|
||||
EXPECT_TRUE(foo.Blah(GetParam()));
|
||||
...
|
||||
}
|
||||
|
||||
TEST_P(FooTest, HasBlahBlah) {
|
||||
...
|
||||
}
|
||||
|
||||
// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test
|
||||
// case with any set of parameters you want. Google Test defines a number
|
||||
// of functions for generating test parameters. They return what we call
|
||||
// (surprise!) parameter generators. Here is a summary of them, which
|
||||
// are all in the testing namespace:
|
||||
//
|
||||
//
|
||||
// Range(begin, end [, step]) - Yields values {begin, begin+step,
|
||||
// begin+step+step, ...}. The values do not
|
||||
// include end. step defaults to 1.
|
||||
// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}.
|
||||
// ValuesIn(container) - Yields values from a C-style array, an STL
|
||||
// ValuesIn(begin,end) container, or an iterator range [begin, end).
|
||||
// Bool() - Yields sequence {false, true}.
|
||||
// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product
|
||||
// for the math savvy) of the values generated
|
||||
// by the N generators.
|
||||
//
|
||||
// For more details, see comments at the definitions of these functions below
|
||||
// in this file.
|
||||
//
|
||||
// The following statement will instantiate tests from the FooTest test case
|
||||
// each with parameter values "meeny", "miny", and "moe".
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(InstantiationName,
|
||||
FooTest,
|
||||
Values("meeny", "miny", "moe"));
|
||||
|
||||
// To distinguish different instances of the pattern, (yes, you
|
||||
// can instantiate it more then once) the first argument to the
|
||||
// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the
|
||||
// actual test case name. Remember to pick unique prefixes for different
|
||||
// instantiations. The tests from the instantiation above will have
|
||||
// these names:
|
||||
//
|
||||
// * InstantiationName/FooTest.DoesBlah/0 for "meeny"
|
||||
// * InstantiationName/FooTest.DoesBlah/1 for "miny"
|
||||
// * InstantiationName/FooTest.DoesBlah/2 for "moe"
|
||||
// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny"
|
||||
// * InstantiationName/FooTest.HasBlahBlah/1 for "miny"
|
||||
// * InstantiationName/FooTest.HasBlahBlah/2 for "moe"
|
||||
//
|
||||
// You can use these names in --gtest_filter.
|
||||
//
|
||||
// This statement will instantiate all tests from FooTest again, each
|
||||
// with parameter values "cat" and "dog":
|
||||
|
||||
const char* pets[] = {"cat", "dog"};
|
||||
INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets));
|
||||
|
||||
// The tests from the instantiation above will have these names:
|
||||
//
|
||||
// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat"
|
||||
// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog"
|
||||
// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat"
|
||||
// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog"
|
||||
//
|
||||
// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests
|
||||
// in the given test case, whether their definitions come before or
|
||||
// AFTER the INSTANTIATE_TEST_CASE_P statement.
|
||||
//
|
||||
// Please also note that generator expressions (including parameters to the
|
||||
// generators) are evaluated in InitGoogleTest(), after main() has started.
|
||||
// This allows the user on one hand, to adjust generator parameters in order
|
||||
// to dynamically determine a set of tests to run and on the other hand,
|
||||
// give the user a chance to inspect the generated tests with Google Test
|
||||
// reflection API before RUN_ALL_TESTS() is executed.
|
||||
//
|
||||
// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc
|
||||
// for more examples.
|
||||
//
|
||||
// In the future, we plan to publish the API for defining new parameter
|
||||
// generators. But for now this interface remains part of the internal
|
||||
// implementation and is subject to change.
|
||||
//
|
||||
//
|
||||
// A parameterized test fixture must be derived from testing::Test and from
|
||||
// testing::WithParamInterface<T>, where T is the type of the parameter
|
||||
// values. Inheriting from TestWithParam<T> satisfies that requirement because
|
||||
// TestWithParam<T> inherits from both Test and WithParamInterface. In more
|
||||
// complicated hierarchies, however, it is occasionally useful to inherit
|
||||
// separately from Test and WithParamInterface. For example:
|
||||
|
||||
class BaseTest : public ::testing::Test {
|
||||
// You can inherit all the usual members for a non-parameterized test
|
||||
// fixture here.
|
||||
};
|
||||
|
||||
class DerivedTest : public BaseTest, public ::testing::WithParamInterface<int> {
|
||||
// The usual test fixture members go here too.
|
||||
};
|
||||
|
||||
TEST_F(BaseTest, HasFoo) {
|
||||
// This is an ordinary non-parameterized test.
|
||||
}
|
||||
|
||||
TEST_P(DerivedTest, DoesBlah) {
|
||||
// GetParam works just the same here as if you inherit from TestWithParam.
|
||||
EXPECT_TRUE(foo.Blah(GetParam()));
|
||||
}
|
||||
|
||||
#endif // 0
|
||||
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
#if !GTEST_OS_SYMBIAN
|
||||
# include <utility>
|
||||
#endif
|
||||
|
||||
// scripts/fuse_gtest.py depends on gtest's own header being #included
|
||||
// *unconditionally*. Therefore these #includes cannot be moved
|
||||
// inside #if GTEST_HAS_PARAM_TEST.
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
#include "gtest/internal/gtest-param-util.h"
|
||||
#include "gtest/internal/gtest-param-util-generated.h"
|
||||
|
||||
#if GTEST_HAS_PARAM_TEST
|
||||
|
||||
namespace testing {
|
||||
|
||||
// Functions producing parameter generators.
|
||||
//
|
||||
// Google Test uses these generators to produce parameters for value-
|
||||
// parameterized tests. When a parameterized test case is instantiated
|
||||
// with a particular generator, Google Test creates and runs tests
|
||||
// for each element in the sequence produced by the generator.
|
||||
//
|
||||
// In the following sample, tests from test case FooTest are instantiated
|
||||
// each three times with parameter values 3, 5, and 8:
|
||||
//
|
||||
// class FooTest : public TestWithParam<int> { ... };
|
||||
//
|
||||
// TEST_P(FooTest, TestThis) {
|
||||
// }
|
||||
// TEST_P(FooTest, TestThat) {
|
||||
// }
|
||||
// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8));
|
||||
//
|
||||
|
||||
// Range() returns generators providing sequences of values in a range.
|
||||
//
|
||||
// Synopsis:
|
||||
// Range(start, end)
|
||||
// - returns a generator producing a sequence of values {start, start+1,
|
||||
// start+2, ..., }.
|
||||
// Range(start, end, step)
|
||||
// - returns a generator producing a sequence of values {start, start+step,
|
||||
// start+step+step, ..., }.
|
||||
// Notes:
|
||||
// * The generated sequences never include end. For example, Range(1, 5)
|
||||
// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2)
|
||||
// returns a generator producing {1, 3, 5, 7}.
|
||||
// * start and end must have the same type. That type may be any integral or
|
||||
// floating-point type or a user defined type satisfying these conditions:
|
||||
// * It must be assignable (have operator=() defined).
|
||||
// * It must have operator+() (operator+(int-compatible type) for
|
||||
// two-operand version).
|
||||
// * It must have operator<() defined.
|
||||
// Elements in the resulting sequences will also have that type.
|
||||
// * Condition start < end must be satisfied in order for resulting sequences
|
||||
// to contain any elements.
|
||||
//
|
||||
template <typename T, typename IncrementT>
|
||||
internal::ParamGenerator<T> Range(T start, T end, IncrementT step) {
|
||||
return internal::ParamGenerator<T>(
|
||||
new internal::RangeGenerator<T, IncrementT>(start, end, step));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
internal::ParamGenerator<T> Range(T start, T end) {
|
||||
return Range(start, end, 1);
|
||||
}
|
||||
|
||||
// ValuesIn() function allows generation of tests with parameters coming from
|
||||
// a container.
|
||||
//
|
||||
// Synopsis:
|
||||
// ValuesIn(const T (&array)[N])
|
||||
// - returns a generator producing sequences with elements from
|
||||
// a C-style array.
|
||||
// ValuesIn(const Container& container)
|
||||
// - returns a generator producing sequences with elements from
|
||||
// an STL-style container.
|
||||
// ValuesIn(Iterator begin, Iterator end)
|
||||
// - returns a generator producing sequences with elements from
|
||||
// a range [begin, end) defined by a pair of STL-style iterators. These
|
||||
// iterators can also be plain C pointers.
|
||||
//
|
||||
// Please note that ValuesIn copies the values from the containers
|
||||
// passed in and keeps them to generate tests in RUN_ALL_TESTS().
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// This instantiates tests from test case StringTest
|
||||
// each with C-string values of "foo", "bar", and "baz":
|
||||
//
|
||||
// const char* strings[] = {"foo", "bar", "baz"};
|
||||
// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings));
|
||||
//
|
||||
// This instantiates tests from test case StlStringTest
|
||||
// each with STL strings with values "a" and "b":
|
||||
//
|
||||
// ::std::vector< ::std::string> GetParameterStrings() {
|
||||
// ::std::vector< ::std::string> v;
|
||||
// v.push_back("a");
|
||||
// v.push_back("b");
|
||||
// return v;
|
||||
// }
|
||||
//
|
||||
// INSTANTIATE_TEST_CASE_P(CharSequence,
|
||||
// StlStringTest,
|
||||
// ValuesIn(GetParameterStrings()));
|
||||
//
|
||||
//
|
||||
// This will also instantiate tests from CharTest
|
||||
// each with parameter values 'a' and 'b':
|
||||
//
|
||||
// ::std::list<char> GetParameterChars() {
|
||||
// ::std::list<char> list;
|
||||
// list.push_back('a');
|
||||
// list.push_back('b');
|
||||
// return list;
|
||||
// }
|
||||
// ::std::list<char> l = GetParameterChars();
|
||||
// INSTANTIATE_TEST_CASE_P(CharSequence2,
|
||||
// CharTest,
|
||||
// ValuesIn(l.begin(), l.end()));
|
||||
//
|
||||
template <typename ForwardIterator>
|
||||
internal::ParamGenerator<
|
||||
typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>
|
||||
ValuesIn(ForwardIterator begin, ForwardIterator end) {
|
||||
typedef typename ::testing::internal::IteratorTraits<ForwardIterator>
|
||||
::value_type ParamType;
|
||||
return internal::ParamGenerator<ParamType>(
|
||||
new internal::ValuesInIteratorRangeGenerator<ParamType>(begin, end));
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
internal::ParamGenerator<T> ValuesIn(const T (&array)[N]) {
|
||||
return ValuesIn(array, array + N);
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
internal::ParamGenerator<typename Container::value_type> ValuesIn(
|
||||
const Container& container) {
|
||||
return ValuesIn(container.begin(), container.end());
|
||||
}
|
||||
|
||||
// Values() allows generating tests from explicitly specified list of
|
||||
// parameters.
|
||||
//
|
||||
// Synopsis:
|
||||
// Values(T v1, T v2, ..., T vN)
|
||||
// - returns a generator producing sequences with elements v1, v2, ..., vN.
|
||||
//
|
||||
// For example, this instantiates tests from test case BarTest each
|
||||
// with values "one", "two", and "three":
|
||||
//
|
||||
// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three"));
|
||||
//
|
||||
// This instantiates tests from test case BazTest each with values 1, 2, 3.5.
|
||||
// The exact type of values will depend on the type of parameter in BazTest.
|
||||
//
|
||||
// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5));
|
||||
//
|
||||
// Currently, Values() supports from 1 to $n parameters.
|
||||
//
|
||||
$range i 1..n
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
|
||||
template <$for j, [[typename T$j]]>
|
||||
internal::ValueArray$i<$for j, [[T$j]]> Values($for j, [[T$j v$j]]) {
|
||||
return internal::ValueArray$i<$for j, [[T$j]]>($for j, [[v$j]]);
|
||||
}
|
||||
|
||||
]]
|
||||
|
||||
// Bool() allows generating tests with parameters in a set of (false, true).
|
||||
//
|
||||
// Synopsis:
|
||||
// Bool()
|
||||
// - returns a generator producing sequences with elements {false, true}.
|
||||
//
|
||||
// It is useful when testing code that depends on Boolean flags. Combinations
|
||||
// of multiple flags can be tested when several Bool()'s are combined using
|
||||
// Combine() function.
|
||||
//
|
||||
// In the following example all tests in the test case FlagDependentTest
|
||||
// will be instantiated twice with parameters false and true.
|
||||
//
|
||||
// class FlagDependentTest : public testing::TestWithParam<bool> {
|
||||
// virtual void SetUp() {
|
||||
// external_flag = GetParam();
|
||||
// }
|
||||
// }
|
||||
// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool());
|
||||
//
|
||||
inline internal::ParamGenerator<bool> Bool() {
|
||||
return Values(false, true);
|
||||
}
|
||||
|
||||
# if GTEST_HAS_COMBINE
|
||||
// Combine() allows the user to combine two or more sequences to produce
|
||||
// values of a Cartesian product of those sequences' elements.
|
||||
//
|
||||
// Synopsis:
|
||||
// Combine(gen1, gen2, ..., genN)
|
||||
// - returns a generator producing sequences with elements coming from
|
||||
// the Cartesian product of elements from the sequences generated by
|
||||
// gen1, gen2, ..., genN. The sequence elements will have a type of
|
||||
// tuple<T1, T2, ..., TN> where T1, T2, ..., TN are the types
|
||||
// of elements from sequences produces by gen1, gen2, ..., genN.
|
||||
//
|
||||
// Combine can have up to $maxtuple arguments. This number is currently limited
|
||||
// by the maximum number of elements in the tuple implementation used by Google
|
||||
// Test.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// This will instantiate tests in test case AnimalTest each one with
|
||||
// the parameter values tuple("cat", BLACK), tuple("cat", WHITE),
|
||||
// tuple("dog", BLACK), and tuple("dog", WHITE):
|
||||
//
|
||||
// enum Color { BLACK, GRAY, WHITE };
|
||||
// class AnimalTest
|
||||
// : public testing::TestWithParam<tuple<const char*, Color> > {...};
|
||||
//
|
||||
// TEST_P(AnimalTest, AnimalLooksNice) {...}
|
||||
//
|
||||
// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest,
|
||||
// Combine(Values("cat", "dog"),
|
||||
// Values(BLACK, WHITE)));
|
||||
//
|
||||
// This will instantiate tests in FlagDependentTest with all variations of two
|
||||
// Boolean flags:
|
||||
//
|
||||
// class FlagDependentTest
|
||||
// : public testing::TestWithParam<tuple(bool, bool)> > {
|
||||
// virtual void SetUp() {
|
||||
// // Assigns external_flag_1 and external_flag_2 values from the tuple.
|
||||
// tie(external_flag_1, external_flag_2) = GetParam();
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// TEST_P(FlagDependentTest, TestFeature1) {
|
||||
// // Test your code using external_flag_1 and external_flag_2 here.
|
||||
// }
|
||||
// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest,
|
||||
// Combine(Bool(), Bool()));
|
||||
//
|
||||
$range i 2..maxtuple
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
|
||||
template <$for j, [[typename Generator$j]]>
|
||||
internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine(
|
||||
$for j, [[const Generator$j& g$j]]) {
|
||||
return internal::CartesianProductHolder$i<$for j, [[Generator$j]]>(
|
||||
$for j, [[g$j]]);
|
||||
}
|
||||
|
||||
]]
|
||||
# endif // GTEST_HAS_COMBINE
|
||||
|
||||
|
||||
|
||||
# define TEST_P(test_case_name, test_name) \
|
||||
class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
|
||||
: public test_case_name { \
|
||||
public: \
|
||||
GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \
|
||||
virtual void TestBody(); \
|
||||
private: \
|
||||
static int AddToRegistry() { \
|
||||
::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
|
||||
GetTestCasePatternHolder<test_case_name>(\
|
||||
#test_case_name, __FILE__, __LINE__)->AddTestPattern(\
|
||||
#test_case_name, \
|
||||
#test_name, \
|
||||
new ::testing::internal::TestMetaFactory< \
|
||||
GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \
|
||||
return 0; \
|
||||
} \
|
||||
static int gtest_registering_dummy_; \
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(\
|
||||
GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \
|
||||
}; \
|
||||
int GTEST_TEST_CLASS_NAME_(test_case_name, \
|
||||
test_name)::gtest_registering_dummy_ = \
|
||||
GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \
|
||||
void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
|
||||
|
||||
# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \
|
||||
::testing::internal::ParamGenerator<test_case_name::ParamType> \
|
||||
gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \
|
||||
int gtest_##prefix##test_case_name##_dummy_ = \
|
||||
::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
|
||||
GetTestCasePatternHolder<test_case_name>(\
|
||||
#test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\
|
||||
#prefix, \
|
||||
>est_##prefix##test_case_name##_EvalGenerator_, \
|
||||
__FILE__, __LINE__)
|
||||
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_HAS_PARAM_TEST
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
|
796
thirdparty/gtest/include/gtest/gtest-printers.h
vendored
Normal file
796
thirdparty/gtest/include/gtest/gtest-printers.h
vendored
Normal file
@ -0,0 +1,796 @@
|
||||
// Copyright 2007, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
|
||||
// Google Test - The Google C++ Testing Framework
|
||||
//
|
||||
// This file implements a universal value printer that can print a
|
||||
// value of any type T:
|
||||
//
|
||||
// void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr);
|
||||
//
|
||||
// A user can teach this function how to print a class type T by
|
||||
// defining either operator<<() or PrintTo() in the namespace that
|
||||
// defines T. More specifically, the FIRST defined function in the
|
||||
// following list will be used (assuming T is defined in namespace
|
||||
// foo):
|
||||
//
|
||||
// 1. foo::PrintTo(const T&, ostream*)
|
||||
// 2. operator<<(ostream&, const T&) defined in either foo or the
|
||||
// global namespace.
|
||||
//
|
||||
// If none of the above is defined, it will print the debug string of
|
||||
// the value if it is a protocol buffer, or print the raw bytes in the
|
||||
// value otherwise.
|
||||
//
|
||||
// To aid debugging: when T is a reference type, the address of the
|
||||
// value is also printed; when T is a (const) char pointer, both the
|
||||
// pointer value and the NUL-terminated string it points to are
|
||||
// printed.
|
||||
//
|
||||
// We also provide some convenient wrappers:
|
||||
//
|
||||
// // Prints a value to a string. For a (const or not) char
|
||||
// // pointer, the NUL-terminated string (but not the pointer) is
|
||||
// // printed.
|
||||
// std::string ::testing::PrintToString(const T& value);
|
||||
//
|
||||
// // Prints a value tersely: for a reference type, the referenced
|
||||
// // value (but not the address) is printed; for a (const or not) char
|
||||
// // pointer, the NUL-terminated string (but not the pointer) is
|
||||
// // printed.
|
||||
// void ::testing::internal::UniversalTersePrint(const T& value, ostream*);
|
||||
//
|
||||
// // Prints value using the type inferred by the compiler. The difference
|
||||
// // from UniversalTersePrint() is that this function prints both the
|
||||
// // pointer and the NUL-terminated string for a (const or not) char pointer.
|
||||
// void ::testing::internal::UniversalPrint(const T& value, ostream*);
|
||||
//
|
||||
// // Prints the fields of a tuple tersely to a string vector, one
|
||||
// // element for each field. Tuple support must be enabled in
|
||||
// // gtest-port.h.
|
||||
// std::vector<string> UniversalTersePrintTupleFieldsToStrings(
|
||||
// const Tuple& value);
|
||||
//
|
||||
// Known limitation:
|
||||
//
|
||||
// The print primitives print the elements of an STL-style container
|
||||
// using the compiler-inferred type of *iter where iter is a
|
||||
// const_iterator of the container. When const_iterator is an input
|
||||
// iterator but not a forward iterator, this inferred type may not
|
||||
// match value_type, and the print output may be incorrect. In
|
||||
// practice, this is rarely a problem as for most containers
|
||||
// const_iterator is a forward iterator. We'll fix this if there's an
|
||||
// actual need for it. Note that this fix cannot rely on value_type
|
||||
// being defined as many user-defined container types don't have
|
||||
// value_type.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
|
||||
|
||||
#include <ostream> // NOLINT
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
|
||||
namespace testing {
|
||||
|
||||
// Definitions in the 'internal' and 'internal2' name spaces are
|
||||
// subject to change without notice. DO NOT USE THEM IN USER CODE!
|
||||
namespace internal2 {
|
||||
|
||||
// Prints the given number of bytes in the given object to the given
|
||||
// ostream.
|
||||
GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes,
|
||||
size_t count,
|
||||
::std::ostream* os);
|
||||
|
||||
// For selecting which printer to use when a given type has neither <<
|
||||
// nor PrintTo().
|
||||
enum TypeKind {
|
||||
kProtobuf, // a protobuf type
|
||||
kConvertibleToInteger, // a type implicitly convertible to BiggestInt
|
||||
// (e.g. a named or unnamed enum type)
|
||||
kOtherType // anything else
|
||||
};
|
||||
|
||||
// TypeWithoutFormatter<T, kTypeKind>::PrintValue(value, os) is called
|
||||
// by the universal printer to print a value of type T when neither
|
||||
// operator<< nor PrintTo() is defined for T, where kTypeKind is the
|
||||
// "kind" of T as defined by enum TypeKind.
|
||||
template <typename T, TypeKind kTypeKind>
|
||||
class TypeWithoutFormatter {
|
||||
public:
|
||||
// This default version is called when kTypeKind is kOtherType.
|
||||
static void PrintValue(const T& value, ::std::ostream* os) {
|
||||
PrintBytesInObjectTo(reinterpret_cast<const unsigned char*>(&value),
|
||||
sizeof(value), os);
|
||||
}
|
||||
};
|
||||
|
||||
// We print a protobuf using its ShortDebugString() when the string
|
||||
// doesn't exceed this many characters; otherwise we print it using
|
||||
// DebugString() for better readability.
|
||||
const size_t kProtobufOneLinerMaxLength = 50;
|
||||
|
||||
template <typename T>
|
||||
class TypeWithoutFormatter<T, kProtobuf> {
|
||||
public:
|
||||
static void PrintValue(const T& value, ::std::ostream* os) {
|
||||
const ::testing::internal::string short_str = value.ShortDebugString();
|
||||
const ::testing::internal::string pretty_str =
|
||||
short_str.length() <= kProtobufOneLinerMaxLength ?
|
||||
short_str : ("\n" + value.DebugString());
|
||||
*os << ("<" + pretty_str + ">");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class TypeWithoutFormatter<T, kConvertibleToInteger> {
|
||||
public:
|
||||
// Since T has no << operator or PrintTo() but can be implicitly
|
||||
// converted to BiggestInt, we print it as a BiggestInt.
|
||||
//
|
||||
// Most likely T is an enum type (either named or unnamed), in which
|
||||
// case printing it as an integer is the desired behavior. In case
|
||||
// T is not an enum, printing it as an integer is the best we can do
|
||||
// given that it has no user-defined printer.
|
||||
static void PrintValue(const T& value, ::std::ostream* os) {
|
||||
const internal::BiggestInt kBigInt = value;
|
||||
*os << kBigInt;
|
||||
}
|
||||
};
|
||||
|
||||
// Prints the given value to the given ostream. If the value is a
|
||||
// protocol message, its debug string is printed; if it's an enum or
|
||||
// of a type implicitly convertible to BiggestInt, it's printed as an
|
||||
// integer; otherwise the bytes in the value are printed. This is
|
||||
// what UniversalPrinter<T>::Print() does when it knows nothing about
|
||||
// type T and T has neither << operator nor PrintTo().
|
||||
//
|
||||
// A user can override this behavior for a class type Foo by defining
|
||||
// a << operator in the namespace where Foo is defined.
|
||||
//
|
||||
// We put this operator in namespace 'internal2' instead of 'internal'
|
||||
// to simplify the implementation, as much code in 'internal' needs to
|
||||
// use << in STL, which would conflict with our own << were it defined
|
||||
// in 'internal'.
|
||||
//
|
||||
// Note that this operator<< takes a generic std::basic_ostream<Char,
|
||||
// CharTraits> type instead of the more restricted std::ostream. If
|
||||
// we define it to take an std::ostream instead, we'll get an
|
||||
// "ambiguous overloads" compiler error when trying to print a type
|
||||
// Foo that supports streaming to std::basic_ostream<Char,
|
||||
// CharTraits>, as the compiler cannot tell whether
|
||||
// operator<<(std::ostream&, const T&) or
|
||||
// operator<<(std::basic_stream<Char, CharTraits>, const Foo&) is more
|
||||
// specific.
|
||||
template <typename Char, typename CharTraits, typename T>
|
||||
::std::basic_ostream<Char, CharTraits>& operator<<(
|
||||
::std::basic_ostream<Char, CharTraits>& os, const T& x) {
|
||||
TypeWithoutFormatter<T,
|
||||
(internal::IsAProtocolMessage<T>::value ? kProtobuf :
|
||||
internal::ImplicitlyConvertible<const T&, internal::BiggestInt>::value ?
|
||||
kConvertibleToInteger : kOtherType)>::PrintValue(x, &os);
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace internal2
|
||||
} // namespace testing
|
||||
|
||||
// This namespace MUST NOT BE NESTED IN ::testing, or the name look-up
|
||||
// magic needed for implementing UniversalPrinter won't work.
|
||||
namespace testing_internal {
|
||||
|
||||
// Used to print a value that is not an STL-style container when the
|
||||
// user doesn't define PrintTo() for it.
|
||||
template <typename T>
|
||||
void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) {
|
||||
// With the following statement, during unqualified name lookup,
|
||||
// testing::internal2::operator<< appears as if it was declared in
|
||||
// the nearest enclosing namespace that contains both
|
||||
// ::testing_internal and ::testing::internal2, i.e. the global
|
||||
// namespace. For more details, refer to the C++ Standard section
|
||||
// 7.3.4-1 [namespace.udir]. This allows us to fall back onto
|
||||
// testing::internal2::operator<< in case T doesn't come with a <<
|
||||
// operator.
|
||||
//
|
||||
// We cannot write 'using ::testing::internal2::operator<<;', which
|
||||
// gcc 3.3 fails to compile due to a compiler bug.
|
||||
using namespace ::testing::internal2; // NOLINT
|
||||
|
||||
// Assuming T is defined in namespace foo, in the next statement,
|
||||
// the compiler will consider all of:
|
||||
//
|
||||
// 1. foo::operator<< (thanks to Koenig look-up),
|
||||
// 2. ::operator<< (as the current namespace is enclosed in ::),
|
||||
// 3. testing::internal2::operator<< (thanks to the using statement above).
|
||||
//
|
||||
// The operator<< whose type matches T best will be picked.
|
||||
//
|
||||
// We deliberately allow #2 to be a candidate, as sometimes it's
|
||||
// impossible to define #1 (e.g. when foo is ::std, defining
|
||||
// anything in it is undefined behavior unless you are a compiler
|
||||
// vendor.).
|
||||
*os << value;
|
||||
}
|
||||
|
||||
} // namespace testing_internal
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
// UniversalPrinter<T>::Print(value, ostream_ptr) prints the given
|
||||
// value to the given ostream. The caller must ensure that
|
||||
// 'ostream_ptr' is not NULL, or the behavior is undefined.
|
||||
//
|
||||
// We define UniversalPrinter as a class template (as opposed to a
|
||||
// function template), as we need to partially specialize it for
|
||||
// reference types, which cannot be done with function templates.
|
||||
template <typename T>
|
||||
class UniversalPrinter;
|
||||
|
||||
template <typename T>
|
||||
void UniversalPrint(const T& value, ::std::ostream* os);
|
||||
|
||||
// Used to print an STL-style container when the user doesn't define
|
||||
// a PrintTo() for it.
|
||||
template <typename C>
|
||||
void DefaultPrintTo(IsContainer /* dummy */,
|
||||
false_type /* is not a pointer */,
|
||||
const C& container, ::std::ostream* os) {
|
||||
const size_t kMaxCount = 32; // The maximum number of elements to print.
|
||||
*os << '{';
|
||||
size_t count = 0;
|
||||
for (typename C::const_iterator it = container.begin();
|
||||
it != container.end(); ++it, ++count) {
|
||||
if (count > 0) {
|
||||
*os << ',';
|
||||
if (count == kMaxCount) { // Enough has been printed.
|
||||
*os << " ...";
|
||||
break;
|
||||
}
|
||||
}
|
||||
*os << ' ';
|
||||
// We cannot call PrintTo(*it, os) here as PrintTo() doesn't
|
||||
// handle *it being a native array.
|
||||
internal::UniversalPrint(*it, os);
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
*os << ' ';
|
||||
}
|
||||
*os << '}';
|
||||
}
|
||||
|
||||
// Used to print a pointer that is neither a char pointer nor a member
|
||||
// pointer, when the user doesn't define PrintTo() for it. (A member
|
||||
// variable pointer or member function pointer doesn't really point to
|
||||
// a location in the address space. Their representation is
|
||||
// implementation-defined. Therefore they will be printed as raw
|
||||
// bytes.)
|
||||
template <typename T>
|
||||
void DefaultPrintTo(IsNotContainer /* dummy */,
|
||||
true_type /* is a pointer */,
|
||||
T* p, ::std::ostream* os) {
|
||||
if (p == NULL) {
|
||||
*os << "NULL";
|
||||
} else {
|
||||
// C++ doesn't allow casting from a function pointer to any object
|
||||
// pointer.
|
||||
//
|
||||
// IsTrue() silences warnings: "Condition is always true",
|
||||
// "unreachable code".
|
||||
if (IsTrue(ImplicitlyConvertible<T*, const void*>::value)) {
|
||||
// T is not a function type. We just call << to print p,
|
||||
// relying on ADL to pick up user-defined << for their pointer
|
||||
// types, if any.
|
||||
*os << p;
|
||||
} else {
|
||||
// T is a function type, so '*os << p' doesn't do what we want
|
||||
// (it just prints p as bool). We want to print p as a const
|
||||
// void*. However, we cannot cast it to const void* directly,
|
||||
// even using reinterpret_cast, as earlier versions of gcc
|
||||
// (e.g. 3.4.5) cannot compile the cast when p is a function
|
||||
// pointer. Casting to UInt64 first solves the problem.
|
||||
*os << reinterpret_cast<const void*>(
|
||||
reinterpret_cast<internal::UInt64>(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Used to print a non-container, non-pointer value when the user
|
||||
// doesn't define PrintTo() for it.
|
||||
template <typename T>
|
||||
void DefaultPrintTo(IsNotContainer /* dummy */,
|
||||
false_type /* is not a pointer */,
|
||||
const T& value, ::std::ostream* os) {
|
||||
::testing_internal::DefaultPrintNonContainerTo(value, os);
|
||||
}
|
||||
|
||||
// Prints the given value using the << operator if it has one;
|
||||
// otherwise prints the bytes in it. This is what
|
||||
// UniversalPrinter<T>::Print() does when PrintTo() is not specialized
|
||||
// or overloaded for type T.
|
||||
//
|
||||
// A user can override this behavior for a class type Foo by defining
|
||||
// an overload of PrintTo() in the namespace where Foo is defined. We
|
||||
// give the user this option as sometimes defining a << operator for
|
||||
// Foo is not desirable (e.g. the coding style may prevent doing it,
|
||||
// or there is already a << operator but it doesn't do what the user
|
||||
// wants).
|
||||
template <typename T>
|
||||
void PrintTo(const T& value, ::std::ostream* os) {
|
||||
// DefaultPrintTo() is overloaded. The type of its first two
|
||||
// arguments determine which version will be picked. If T is an
|
||||
// STL-style container, the version for container will be called; if
|
||||
// T is a pointer, the pointer version will be called; otherwise the
|
||||
// generic version will be called.
|
||||
//
|
||||
// Note that we check for container types here, prior to we check
|
||||
// for protocol message types in our operator<<. The rationale is:
|
||||
//
|
||||
// For protocol messages, we want to give people a chance to
|
||||
// override Google Mock's format by defining a PrintTo() or
|
||||
// operator<<. For STL containers, other formats can be
|
||||
// incompatible with Google Mock's format for the container
|
||||
// elements; therefore we check for container types here to ensure
|
||||
// that our format is used.
|
||||
//
|
||||
// The second argument of DefaultPrintTo() is needed to bypass a bug
|
||||
// in Symbian's C++ compiler that prevents it from picking the right
|
||||
// overload between:
|
||||
//
|
||||
// PrintTo(const T& x, ...);
|
||||
// PrintTo(T* x, ...);
|
||||
DefaultPrintTo(IsContainerTest<T>(0), is_pointer<T>(), value, os);
|
||||
}
|
||||
|
||||
// The following list of PrintTo() overloads tells
|
||||
// UniversalPrinter<T>::Print() how to print standard types (built-in
|
||||
// types, strings, plain arrays, and pointers).
|
||||
|
||||
// Overloads for various char types.
|
||||
GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os);
|
||||
GTEST_API_ void PrintTo(signed char c, ::std::ostream* os);
|
||||
inline void PrintTo(char c, ::std::ostream* os) {
|
||||
// When printing a plain char, we always treat it as unsigned. This
|
||||
// way, the output won't be affected by whether the compiler thinks
|
||||
// char is signed or not.
|
||||
PrintTo(static_cast<unsigned char>(c), os);
|
||||
}
|
||||
|
||||
// Overloads for other simple built-in types.
|
||||
inline void PrintTo(bool x, ::std::ostream* os) {
|
||||
*os << (x ? "true" : "false");
|
||||
}
|
||||
|
||||
// Overload for wchar_t type.
|
||||
// Prints a wchar_t as a symbol if it is printable or as its internal
|
||||
// code otherwise and also as its decimal code (except for L'\0').
|
||||
// The L'\0' char is printed as "L'\\0'". The decimal code is printed
|
||||
// as signed integer when wchar_t is implemented by the compiler
|
||||
// as a signed type and is printed as an unsigned integer when wchar_t
|
||||
// is implemented as an unsigned type.
|
||||
GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os);
|
||||
|
||||
// Overloads for C strings.
|
||||
GTEST_API_ void PrintTo(const char* s, ::std::ostream* os);
|
||||
inline void PrintTo(char* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const char*>(s), os);
|
||||
}
|
||||
|
||||
// signed/unsigned char is often used for representing binary data, so
|
||||
// we print pointers to it as void* to be safe.
|
||||
inline void PrintTo(const signed char* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const void*>(s), os);
|
||||
}
|
||||
inline void PrintTo(signed char* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const void*>(s), os);
|
||||
}
|
||||
inline void PrintTo(const unsigned char* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const void*>(s), os);
|
||||
}
|
||||
inline void PrintTo(unsigned char* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const void*>(s), os);
|
||||
}
|
||||
|
||||
// MSVC can be configured to define wchar_t as a typedef of unsigned
|
||||
// short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native
|
||||
// type. When wchar_t is a typedef, defining an overload for const
|
||||
// wchar_t* would cause unsigned short* be printed as a wide string,
|
||||
// possibly causing invalid memory accesses.
|
||||
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||
// Overloads for wide C strings
|
||||
GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os);
|
||||
inline void PrintTo(wchar_t* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const wchar_t*>(s), os);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Overload for C arrays. Multi-dimensional arrays are printed
|
||||
// properly.
|
||||
|
||||
// Prints the given number of elements in an array, without printing
|
||||
// the curly braces.
|
||||
template <typename T>
|
||||
void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) {
|
||||
UniversalPrint(a[0], os);
|
||||
for (size_t i = 1; i != count; i++) {
|
||||
*os << ", ";
|
||||
UniversalPrint(a[i], os);
|
||||
}
|
||||
}
|
||||
|
||||
// Overloads for ::string and ::std::string.
|
||||
#if GTEST_HAS_GLOBAL_STRING
|
||||
GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os);
|
||||
inline void PrintTo(const ::string& s, ::std::ostream* os) {
|
||||
PrintStringTo(s, os);
|
||||
}
|
||||
#endif // GTEST_HAS_GLOBAL_STRING
|
||||
|
||||
GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os);
|
||||
inline void PrintTo(const ::std::string& s, ::std::ostream* os) {
|
||||
PrintStringTo(s, os);
|
||||
}
|
||||
|
||||
// Overloads for ::wstring and ::std::wstring.
|
||||
#if GTEST_HAS_GLOBAL_WSTRING
|
||||
GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os);
|
||||
inline void PrintTo(const ::wstring& s, ::std::ostream* os) {
|
||||
PrintWideStringTo(s, os);
|
||||
}
|
||||
#endif // GTEST_HAS_GLOBAL_WSTRING
|
||||
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os);
|
||||
inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) {
|
||||
PrintWideStringTo(s, os);
|
||||
}
|
||||
#endif // GTEST_HAS_STD_WSTRING
|
||||
|
||||
#if GTEST_HAS_TR1_TUPLE
|
||||
// Overload for ::std::tr1::tuple. Needed for printing function arguments,
|
||||
// which are packed as tuples.
|
||||
|
||||
// Helper function for printing a tuple. T must be instantiated with
|
||||
// a tuple type.
|
||||
template <typename T>
|
||||
void PrintTupleTo(const T& t, ::std::ostream* os);
|
||||
|
||||
// Overloaded PrintTo() for tuples of various arities. We support
|
||||
// tuples of up-to 10 fields. The following implementation works
|
||||
// regardless of whether tr1::tuple is implemented using the
|
||||
// non-standard variadic template feature or not.
|
||||
|
||||
inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1>
|
||||
void PrintTo(const ::std::tr1::tuple<T1>& t, ::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2>& t, ::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2, T3>& t, ::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4>& t, ::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5>& t,
|
||||
::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename T6>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6>& t,
|
||||
::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename T6, typename T7>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7>& t,
|
||||
::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename T6, typename T7, typename T8>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8>& t,
|
||||
::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename T6, typename T7, typename T8, typename T9>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9>& t,
|
||||
::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename T6, typename T7, typename T8, typename T9, typename T10>
|
||||
void PrintTo(
|
||||
const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>& t,
|
||||
::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
#endif // GTEST_HAS_TR1_TUPLE
|
||||
|
||||
// Overload for std::pair.
|
||||
template <typename T1, typename T2>
|
||||
void PrintTo(const ::std::pair<T1, T2>& value, ::std::ostream* os) {
|
||||
*os << '(';
|
||||
// We cannot use UniversalPrint(value.first, os) here, as T1 may be
|
||||
// a reference type. The same for printing value.second.
|
||||
UniversalPrinter<T1>::Print(value.first, os);
|
||||
*os << ", ";
|
||||
UniversalPrinter<T2>::Print(value.second, os);
|
||||
*os << ')';
|
||||
}
|
||||
|
||||
// Implements printing a non-reference type T by letting the compiler
|
||||
// pick the right overload of PrintTo() for T.
|
||||
template <typename T>
|
||||
class UniversalPrinter {
|
||||
public:
|
||||
// MSVC warns about adding const to a function type, so we want to
|
||||
// disable the warning.
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(push) // Saves the current warning state.
|
||||
# pragma warning(disable:4180) // Temporarily disables warning 4180.
|
||||
#endif // _MSC_VER
|
||||
|
||||
// Note: we deliberately don't call this PrintTo(), as that name
|
||||
// conflicts with ::testing::internal::PrintTo in the body of the
|
||||
// function.
|
||||
static void Print(const T& value, ::std::ostream* os) {
|
||||
// By default, ::testing::internal::PrintTo() is used for printing
|
||||
// the value.
|
||||
//
|
||||
// Thanks to Koenig look-up, if T is a class and has its own
|
||||
// PrintTo() function defined in its namespace, that function will
|
||||
// be visible here. Since it is more specific than the generic ones
|
||||
// in ::testing::internal, it will be picked by the compiler in the
|
||||
// following statement - exactly what we want.
|
||||
PrintTo(value, os);
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(pop) // Restores the warning state.
|
||||
#endif // _MSC_VER
|
||||
};
|
||||
|
||||
// UniversalPrintArray(begin, len, os) prints an array of 'len'
|
||||
// elements, starting at address 'begin'.
|
||||
template <typename T>
|
||||
void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) {
|
||||
if (len == 0) {
|
||||
*os << "{}";
|
||||
} else {
|
||||
*os << "{ ";
|
||||
const size_t kThreshold = 18;
|
||||
const size_t kChunkSize = 8;
|
||||
// If the array has more than kThreshold elements, we'll have to
|
||||
// omit some details by printing only the first and the last
|
||||
// kChunkSize elements.
|
||||
// TODO(wan@google.com): let the user control the threshold using a flag.
|
||||
if (len <= kThreshold) {
|
||||
PrintRawArrayTo(begin, len, os);
|
||||
} else {
|
||||
PrintRawArrayTo(begin, kChunkSize, os);
|
||||
*os << ", ..., ";
|
||||
PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os);
|
||||
}
|
||||
*os << " }";
|
||||
}
|
||||
}
|
||||
// This overload prints a (const) char array compactly.
|
||||
GTEST_API_ void UniversalPrintArray(const char* begin,
|
||||
size_t len,
|
||||
::std::ostream* os);
|
||||
|
||||
// Implements printing an array type T[N].
|
||||
template <typename T, size_t N>
|
||||
class UniversalPrinter<T[N]> {
|
||||
public:
|
||||
// Prints the given array, omitting some elements when there are too
|
||||
// many.
|
||||
static void Print(const T (&a)[N], ::std::ostream* os) {
|
||||
UniversalPrintArray(a, N, os);
|
||||
}
|
||||
};
|
||||
|
||||
// Implements printing a reference type T&.
|
||||
template <typename T>
|
||||
class UniversalPrinter<T&> {
|
||||
public:
|
||||
// MSVC warns about adding const to a function type, so we want to
|
||||
// disable the warning.
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(push) // Saves the current warning state.
|
||||
# pragma warning(disable:4180) // Temporarily disables warning 4180.
|
||||
#endif // _MSC_VER
|
||||
|
||||
static void Print(const T& value, ::std::ostream* os) {
|
||||
// Prints the address of the value. We use reinterpret_cast here
|
||||
// as static_cast doesn't compile when T is a function type.
|
||||
*os << "@" << reinterpret_cast<const void*>(&value) << " ";
|
||||
|
||||
// Then prints the value itself.
|
||||
UniversalPrint(value, os);
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(pop) // Restores the warning state.
|
||||
#endif // _MSC_VER
|
||||
};
|
||||
|
||||
// Prints a value tersely: for a reference type, the referenced value
|
||||
// (but not the address) is printed; for a (const) char pointer, the
|
||||
// NUL-terminated string (but not the pointer) is printed.
|
||||
template <typename T>
|
||||
void UniversalTersePrint(const T& value, ::std::ostream* os) {
|
||||
UniversalPrint(value, os);
|
||||
}
|
||||
inline void UniversalTersePrint(const char* str, ::std::ostream* os) {
|
||||
if (str == NULL) {
|
||||
*os << "NULL";
|
||||
} else {
|
||||
UniversalPrint(string(str), os);
|
||||
}
|
||||
}
|
||||
inline void UniversalTersePrint(char* str, ::std::ostream* os) {
|
||||
UniversalTersePrint(static_cast<const char*>(str), os);
|
||||
}
|
||||
|
||||
// Prints a value using the type inferred by the compiler. The
|
||||
// difference between this and UniversalTersePrint() is that for a
|
||||
// (const) char pointer, this prints both the pointer and the
|
||||
// NUL-terminated string.
|
||||
template <typename T>
|
||||
void UniversalPrint(const T& value, ::std::ostream* os) {
|
||||
UniversalPrinter<T>::Print(value, os);
|
||||
}
|
||||
|
||||
#if GTEST_HAS_TR1_TUPLE
|
||||
typedef ::std::vector<string> Strings;
|
||||
|
||||
// This helper template allows PrintTo() for tuples and
|
||||
// UniversalTersePrintTupleFieldsToStrings() to be defined by
|
||||
// induction on the number of tuple fields. The idea is that
|
||||
// TuplePrefixPrinter<N>::PrintPrefixTo(t, os) prints the first N
|
||||
// fields in tuple t, and can be defined in terms of
|
||||
// TuplePrefixPrinter<N - 1>.
|
||||
|
||||
// The inductive case.
|
||||
template <size_t N>
|
||||
struct TuplePrefixPrinter {
|
||||
// Prints the first N fields of a tuple.
|
||||
template <typename Tuple>
|
||||
static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
|
||||
TuplePrefixPrinter<N - 1>::PrintPrefixTo(t, os);
|
||||
*os << ", ";
|
||||
UniversalPrinter<typename ::std::tr1::tuple_element<N - 1, Tuple>::type>
|
||||
::Print(::std::tr1::get<N - 1>(t), os);
|
||||
}
|
||||
|
||||
// Tersely prints the first N fields of a tuple to a string vector,
|
||||
// one element for each field.
|
||||
template <typename Tuple>
|
||||
static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) {
|
||||
TuplePrefixPrinter<N - 1>::TersePrintPrefixToStrings(t, strings);
|
||||
::std::stringstream ss;
|
||||
UniversalTersePrint(::std::tr1::get<N - 1>(t), &ss);
|
||||
strings->push_back(ss.str());
|
||||
}
|
||||
};
|
||||
|
||||
// Base cases.
|
||||
template <>
|
||||
struct TuplePrefixPrinter<0> {
|
||||
template <typename Tuple>
|
||||
static void PrintPrefixTo(const Tuple&, ::std::ostream*) {}
|
||||
|
||||
template <typename Tuple>
|
||||
static void TersePrintPrefixToStrings(const Tuple&, Strings*) {}
|
||||
};
|
||||
// We have to specialize the entire TuplePrefixPrinter<> class
|
||||
// template here, even though the definition of
|
||||
// TersePrintPrefixToStrings() is the same as the generic version, as
|
||||
// Embarcadero (formerly CodeGear, formerly Borland) C++ doesn't
|
||||
// support specializing a method template of a class template.
|
||||
template <>
|
||||
struct TuplePrefixPrinter<1> {
|
||||
template <typename Tuple>
|
||||
static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
|
||||
UniversalPrinter<typename ::std::tr1::tuple_element<0, Tuple>::type>::
|
||||
Print(::std::tr1::get<0>(t), os);
|
||||
}
|
||||
|
||||
template <typename Tuple>
|
||||
static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) {
|
||||
::std::stringstream ss;
|
||||
UniversalTersePrint(::std::tr1::get<0>(t), &ss);
|
||||
strings->push_back(ss.str());
|
||||
}
|
||||
};
|
||||
|
||||
// Helper function for printing a tuple. T must be instantiated with
|
||||
// a tuple type.
|
||||
template <typename T>
|
||||
void PrintTupleTo(const T& t, ::std::ostream* os) {
|
||||
*os << "(";
|
||||
TuplePrefixPrinter< ::std::tr1::tuple_size<T>::value>::
|
||||
PrintPrefixTo(t, os);
|
||||
*os << ")";
|
||||
}
|
||||
|
||||
// Prints the fields of a tuple tersely to a string vector, one
|
||||
// element for each field. See the comment before
|
||||
// UniversalTersePrint() for how we define "tersely".
|
||||
template <typename Tuple>
|
||||
Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) {
|
||||
Strings result;
|
||||
TuplePrefixPrinter< ::std::tr1::tuple_size<Tuple>::value>::
|
||||
TersePrintPrefixToStrings(value, &result);
|
||||
return result;
|
||||
}
|
||||
#endif // GTEST_HAS_TR1_TUPLE
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T>
|
||||
::std::string PrintToString(const T& value) {
|
||||
::std::stringstream ss;
|
||||
internal::UniversalTersePrint(value, &ss);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
|
232
thirdparty/gtest/include/gtest/gtest-spi.h
vendored
Normal file
232
thirdparty/gtest/include/gtest/gtest-spi.h
vendored
Normal file
@ -0,0 +1,232 @@
|
||||
// Copyright 2007, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
//
|
||||
// Utilities for testing Google Test itself and code that uses Google Test
|
||||
// (e.g. frameworks built on top of Google Test).
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace testing {
|
||||
|
||||
// This helper class can be used to mock out Google Test failure reporting
|
||||
// so that we can test Google Test or code that builds on Google Test.
|
||||
//
|
||||
// An object of this class appends a TestPartResult object to the
|
||||
// TestPartResultArray object given in the constructor whenever a Google Test
|
||||
// failure is reported. It can either intercept only failures that are
|
||||
// generated in the same thread that created this object or it can intercept
|
||||
// all generated failures. The scope of this mock object can be controlled with
|
||||
// the second argument to the two arguments constructor.
|
||||
class GTEST_API_ ScopedFakeTestPartResultReporter
|
||||
: public TestPartResultReporterInterface {
|
||||
public:
|
||||
// The two possible mocking modes of this object.
|
||||
enum InterceptMode {
|
||||
INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures.
|
||||
INTERCEPT_ALL_THREADS // Intercepts all failures.
|
||||
};
|
||||
|
||||
// The c'tor sets this object as the test part result reporter used
|
||||
// by Google Test. The 'result' parameter specifies where to report the
|
||||
// results. This reporter will only catch failures generated in the current
|
||||
// thread. DEPRECATED
|
||||
explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result);
|
||||
|
||||
// Same as above, but you can choose the interception scope of this object.
|
||||
ScopedFakeTestPartResultReporter(InterceptMode intercept_mode,
|
||||
TestPartResultArray* result);
|
||||
|
||||
// The d'tor restores the previous test part result reporter.
|
||||
virtual ~ScopedFakeTestPartResultReporter();
|
||||
|
||||
// Appends the TestPartResult object to the TestPartResultArray
|
||||
// received in the constructor.
|
||||
//
|
||||
// This method is from the TestPartResultReporterInterface
|
||||
// interface.
|
||||
virtual void ReportTestPartResult(const TestPartResult& result);
|
||||
private:
|
||||
void Init();
|
||||
|
||||
const InterceptMode intercept_mode_;
|
||||
TestPartResultReporterInterface* old_reporter_;
|
||||
TestPartResultArray* const result_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter);
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
// A helper class for implementing EXPECT_FATAL_FAILURE() and
|
||||
// EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given
|
||||
// TestPartResultArray contains exactly one failure that has the given
|
||||
// type and contains the given substring. If that's not the case, a
|
||||
// non-fatal failure will be generated.
|
||||
class GTEST_API_ SingleFailureChecker {
|
||||
public:
|
||||
// The constructor remembers the arguments.
|
||||
SingleFailureChecker(const TestPartResultArray* results,
|
||||
TestPartResult::Type type,
|
||||
const string& substr);
|
||||
~SingleFailureChecker();
|
||||
private:
|
||||
const TestPartResultArray* const results_;
|
||||
const TestPartResult::Type type_;
|
||||
const string substr_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace testing
|
||||
|
||||
// A set of macros for testing Google Test assertions or code that's expected
|
||||
// to generate Google Test fatal failures. It verifies that the given
|
||||
// statement will cause exactly one fatal Google Test failure with 'substr'
|
||||
// being part of the failure message.
|
||||
//
|
||||
// There are two different versions of this macro. EXPECT_FATAL_FAILURE only
|
||||
// affects and considers failures generated in the current thread and
|
||||
// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
|
||||
//
|
||||
// The verification of the assertion is done correctly even when the statement
|
||||
// throws an exception or aborts the current function.
|
||||
//
|
||||
// Known restrictions:
|
||||
// - 'statement' cannot reference local non-static variables or
|
||||
// non-static members of the current object.
|
||||
// - 'statement' cannot return a value.
|
||||
// - You cannot stream a failure message to this macro.
|
||||
//
|
||||
// Note that even though the implementations of the following two
|
||||
// macros are much alike, we cannot refactor them to use a common
|
||||
// helper macro, due to some peculiarity in how the preprocessor
|
||||
// works. The AcceptsMacroThatExpandsToUnprotectedComma test in
|
||||
// gtest_unittest.cc will fail to compile if we do that.
|
||||
#define EXPECT_FATAL_FAILURE(statement, substr) \
|
||||
do { \
|
||||
class GTestExpectFatalFailureHelper {\
|
||||
public:\
|
||||
static void Execute() { statement; }\
|
||||
};\
|
||||
::testing::TestPartResultArray gtest_failures;\
|
||||
::testing::internal::SingleFailureChecker gtest_checker(\
|
||||
>est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
|
||||
{\
|
||||
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
|
||||
::testing::ScopedFakeTestPartResultReporter:: \
|
||||
INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\
|
||||
GTestExpectFatalFailureHelper::Execute();\
|
||||
}\
|
||||
} while (::testing::internal::AlwaysFalse())
|
||||
|
||||
#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
|
||||
do { \
|
||||
class GTestExpectFatalFailureHelper {\
|
||||
public:\
|
||||
static void Execute() { statement; }\
|
||||
};\
|
||||
::testing::TestPartResultArray gtest_failures;\
|
||||
::testing::internal::SingleFailureChecker gtest_checker(\
|
||||
>est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
|
||||
{\
|
||||
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
|
||||
::testing::ScopedFakeTestPartResultReporter:: \
|
||||
INTERCEPT_ALL_THREADS, >est_failures);\
|
||||
GTestExpectFatalFailureHelper::Execute();\
|
||||
}\
|
||||
} while (::testing::internal::AlwaysFalse())
|
||||
|
||||
// A macro for testing Google Test assertions or code that's expected to
|
||||
// generate Google Test non-fatal failures. It asserts that the given
|
||||
// statement will cause exactly one non-fatal Google Test failure with 'substr'
|
||||
// being part of the failure message.
|
||||
//
|
||||
// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only
|
||||
// affects and considers failures generated in the current thread and
|
||||
// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
|
||||
//
|
||||
// 'statement' is allowed to reference local variables and members of
|
||||
// the current object.
|
||||
//
|
||||
// The verification of the assertion is done correctly even when the statement
|
||||
// throws an exception or aborts the current function.
|
||||
//
|
||||
// Known restrictions:
|
||||
// - You cannot stream a failure message to this macro.
|
||||
//
|
||||
// Note that even though the implementations of the following two
|
||||
// macros are much alike, we cannot refactor them to use a common
|
||||
// helper macro, due to some peculiarity in how the preprocessor
|
||||
// works. If we do that, the code won't compile when the user gives
|
||||
// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that
|
||||
// expands to code containing an unprotected comma. The
|
||||
// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc
|
||||
// catches that.
|
||||
//
|
||||
// For the same reason, we have to write
|
||||
// if (::testing::internal::AlwaysTrue()) { statement; }
|
||||
// instead of
|
||||
// GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
|
||||
// to avoid an MSVC warning on unreachable code.
|
||||
#define EXPECT_NONFATAL_FAILURE(statement, substr) \
|
||||
do {\
|
||||
::testing::TestPartResultArray gtest_failures;\
|
||||
::testing::internal::SingleFailureChecker gtest_checker(\
|
||||
>est_failures, ::testing::TestPartResult::kNonFatalFailure, \
|
||||
(substr));\
|
||||
{\
|
||||
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
|
||||
::testing::ScopedFakeTestPartResultReporter:: \
|
||||
INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\
|
||||
if (::testing::internal::AlwaysTrue()) { statement; }\
|
||||
}\
|
||||
} while (::testing::internal::AlwaysFalse())
|
||||
|
||||
#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
|
||||
do {\
|
||||
::testing::TestPartResultArray gtest_failures;\
|
||||
::testing::internal::SingleFailureChecker gtest_checker(\
|
||||
>est_failures, ::testing::TestPartResult::kNonFatalFailure, \
|
||||
(substr));\
|
||||
{\
|
||||
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
|
||||
::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS,\
|
||||
>est_failures);\
|
||||
if (::testing::internal::AlwaysTrue()) { statement; }\
|
||||
}\
|
||||
} while (::testing::internal::AlwaysFalse())
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_
|
176
thirdparty/gtest/include/gtest/gtest-test-part.h
vendored
Normal file
176
thirdparty/gtest/include/gtest/gtest-test-part.h
vendored
Normal file
@ -0,0 +1,176 @@
|
||||
// Copyright 2008, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: mheule@google.com (Markus Heule)
|
||||
//
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
|
||||
|
||||
#include <iosfwd>
|
||||
#include <vector>
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
#include "gtest/internal/gtest-string.h"
|
||||
|
||||
namespace testing {
|
||||
|
||||
// A copyable object representing the result of a test part (i.e. an
|
||||
// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()).
|
||||
//
|
||||
// Don't inherit from TestPartResult as its destructor is not virtual.
|
||||
class GTEST_API_ TestPartResult {
|
||||
public:
|
||||
// The possible outcomes of a test part (i.e. an assertion or an
|
||||
// explicit SUCCEED(), FAIL(), or ADD_FAILURE()).
|
||||
enum Type {
|
||||
kSuccess, // Succeeded.
|
||||
kNonFatalFailure, // Failed but the test can continue.
|
||||
kFatalFailure // Failed and the test should be terminated.
|
||||
};
|
||||
|
||||
// C'tor. TestPartResult does NOT have a default constructor.
|
||||
// Always use this constructor (with parameters) to create a
|
||||
// TestPartResult object.
|
||||
TestPartResult(Type a_type,
|
||||
const char* a_file_name,
|
||||
int a_line_number,
|
||||
const char* a_message)
|
||||
: type_(a_type),
|
||||
file_name_(a_file_name),
|
||||
line_number_(a_line_number),
|
||||
summary_(ExtractSummary(a_message)),
|
||||
message_(a_message) {
|
||||
}
|
||||
|
||||
// Gets the outcome of the test part.
|
||||
Type type() const { return type_; }
|
||||
|
||||
// Gets the name of the source file where the test part took place, or
|
||||
// NULL if it's unknown.
|
||||
const char* file_name() const { return file_name_.c_str(); }
|
||||
|
||||
// Gets the line in the source file where the test part took place,
|
||||
// or -1 if it's unknown.
|
||||
int line_number() const { return line_number_; }
|
||||
|
||||
// Gets the summary of the failure message.
|
||||
const char* summary() const { return summary_.c_str(); }
|
||||
|
||||
// Gets the message associated with the test part.
|
||||
const char* message() const { return message_.c_str(); }
|
||||
|
||||
// Returns true iff the test part passed.
|
||||
bool passed() const { return type_ == kSuccess; }
|
||||
|
||||
// Returns true iff the test part failed.
|
||||
bool failed() const { return type_ != kSuccess; }
|
||||
|
||||
// Returns true iff the test part non-fatally failed.
|
||||
bool nonfatally_failed() const { return type_ == kNonFatalFailure; }
|
||||
|
||||
// Returns true iff the test part fatally failed.
|
||||
bool fatally_failed() const { return type_ == kFatalFailure; }
|
||||
private:
|
||||
Type type_;
|
||||
|
||||
// Gets the summary of the failure message by omitting the stack
|
||||
// trace in it.
|
||||
static internal::String ExtractSummary(const char* message);
|
||||
|
||||
// The name of the source file where the test part took place, or
|
||||
// NULL if the source file is unknown.
|
||||
internal::String file_name_;
|
||||
// The line in the source file where the test part took place, or -1
|
||||
// if the line number is unknown.
|
||||
int line_number_;
|
||||
internal::String summary_; // The test failure summary.
|
||||
internal::String message_; // The test failure message.
|
||||
};
|
||||
|
||||
// Prints a TestPartResult object.
|
||||
std::ostream& operator<<(std::ostream& os, const TestPartResult& result);
|
||||
|
||||
// An array of TestPartResult objects.
|
||||
//
|
||||
// Don't inherit from TestPartResultArray as its destructor is not
|
||||
// virtual.
|
||||
class GTEST_API_ TestPartResultArray {
|
||||
public:
|
||||
TestPartResultArray() {}
|
||||
|
||||
// Appends the given TestPartResult to the array.
|
||||
void Append(const TestPartResult& result);
|
||||
|
||||
// Returns the TestPartResult at the given index (0-based).
|
||||
const TestPartResult& GetTestPartResult(int index) const;
|
||||
|
||||
// Returns the number of TestPartResult objects in the array.
|
||||
int size() const;
|
||||
|
||||
private:
|
||||
std::vector<TestPartResult> array_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray);
|
||||
};
|
||||
|
||||
// This interface knows how to report a test part result.
|
||||
class TestPartResultReporterInterface {
|
||||
public:
|
||||
virtual ~TestPartResultReporterInterface() {}
|
||||
|
||||
virtual void ReportTestPartResult(const TestPartResult& result) = 0;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a
|
||||
// statement generates new fatal failures. To do so it registers itself as the
|
||||
// current test part result reporter. Besides checking if fatal failures were
|
||||
// reported, it only delegates the reporting to the former result reporter.
|
||||
// The original result reporter is restored in the destructor.
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
|
||||
class GTEST_API_ HasNewFatalFailureHelper
|
||||
: public TestPartResultReporterInterface {
|
||||
public:
|
||||
HasNewFatalFailureHelper();
|
||||
virtual ~HasNewFatalFailureHelper();
|
||||
virtual void ReportTestPartResult(const TestPartResult& result);
|
||||
bool has_new_fatal_failure() const { return has_new_fatal_failure_; }
|
||||
private:
|
||||
bool has_new_fatal_failure_;
|
||||
TestPartResultReporterInterface* original_reporter_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
|
259
thirdparty/gtest/include/gtest/gtest-typed-test.h
vendored
Normal file
259
thirdparty/gtest/include/gtest/gtest-typed-test.h
vendored
Normal file
@ -0,0 +1,259 @@
|
||||
// Copyright 2008 Google Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
|
||||
|
||||
// This header implements typed tests and type-parameterized tests.
|
||||
|
||||
// Typed (aka type-driven) tests repeat the same test for types in a
|
||||
// list. You must know which types you want to test with when writing
|
||||
// typed tests. Here's how you do it:
|
||||
|
||||
#if 0
|
||||
|
||||
// First, define a fixture class template. It should be parameterized
|
||||
// by a type. Remember to derive it from testing::Test.
|
||||
template <typename T>
|
||||
class FooTest : public testing::Test {
|
||||
public:
|
||||
...
|
||||
typedef std::list<T> List;
|
||||
static T shared_;
|
||||
T value_;
|
||||
};
|
||||
|
||||
// Next, associate a list of types with the test case, which will be
|
||||
// repeated for each type in the list. The typedef is necessary for
|
||||
// the macro to parse correctly.
|
||||
typedef testing::Types<char, int, unsigned int> MyTypes;
|
||||
TYPED_TEST_CASE(FooTest, MyTypes);
|
||||
|
||||
// If the type list contains only one type, you can write that type
|
||||
// directly without Types<...>:
|
||||
// TYPED_TEST_CASE(FooTest, int);
|
||||
|
||||
// Then, use TYPED_TEST() instead of TEST_F() to define as many typed
|
||||
// tests for this test case as you want.
|
||||
TYPED_TEST(FooTest, DoesBlah) {
|
||||
// Inside a test, refer to TypeParam to get the type parameter.
|
||||
// Since we are inside a derived class template, C++ requires use to
|
||||
// visit the members of FooTest via 'this'.
|
||||
TypeParam n = this->value_;
|
||||
|
||||
// To visit static members of the fixture, add the TestFixture::
|
||||
// prefix.
|
||||
n += TestFixture::shared_;
|
||||
|
||||
// To refer to typedefs in the fixture, add the "typename
|
||||
// TestFixture::" prefix.
|
||||
typename TestFixture::List values;
|
||||
values.push_back(n);
|
||||
...
|
||||
}
|
||||
|
||||
TYPED_TEST(FooTest, HasPropertyA) { ... }
|
||||
|
||||
#endif // 0
|
||||
|
||||
// Type-parameterized tests are abstract test patterns parameterized
|
||||
// by a type. Compared with typed tests, type-parameterized tests
|
||||
// allow you to define the test pattern without knowing what the type
|
||||
// parameters are. The defined pattern can be instantiated with
|
||||
// different types any number of times, in any number of translation
|
||||
// units.
|
||||
//
|
||||
// If you are designing an interface or concept, you can define a
|
||||
// suite of type-parameterized tests to verify properties that any
|
||||
// valid implementation of the interface/concept should have. Then,
|
||||
// each implementation can easily instantiate the test suite to verify
|
||||
// that it conforms to the requirements, without having to write
|
||||
// similar tests repeatedly. Here's an example:
|
||||
|
||||
#if 0
|
||||
|
||||
// First, define a fixture class template. It should be parameterized
|
||||
// by a type. Remember to derive it from testing::Test.
|
||||
template <typename T>
|
||||
class FooTest : public testing::Test {
|
||||
...
|
||||
};
|
||||
|
||||
// Next, declare that you will define a type-parameterized test case
|
||||
// (the _P suffix is for "parameterized" or "pattern", whichever you
|
||||
// prefer):
|
||||
TYPED_TEST_CASE_P(FooTest);
|
||||
|
||||
// Then, use TYPED_TEST_P() to define as many type-parameterized tests
|
||||
// for this type-parameterized test case as you want.
|
||||
TYPED_TEST_P(FooTest, DoesBlah) {
|
||||
// Inside a test, refer to TypeParam to get the type parameter.
|
||||
TypeParam n = 0;
|
||||
...
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FooTest, HasPropertyA) { ... }
|
||||
|
||||
// Now the tricky part: you need to register all test patterns before
|
||||
// you can instantiate them. The first argument of the macro is the
|
||||
// test case name; the rest are the names of the tests in this test
|
||||
// case.
|
||||
REGISTER_TYPED_TEST_CASE_P(FooTest,
|
||||
DoesBlah, HasPropertyA);
|
||||
|
||||
// Finally, you are free to instantiate the pattern with the types you
|
||||
// want. If you put the above code in a header file, you can #include
|
||||
// it in multiple C++ source files and instantiate it multiple times.
|
||||
//
|
||||
// To distinguish different instances of the pattern, the first
|
||||
// argument to the INSTANTIATE_* macro is a prefix that will be added
|
||||
// to the actual test case name. Remember to pick unique prefixes for
|
||||
// different instances.
|
||||
typedef testing::Types<char, int, unsigned int> MyTypes;
|
||||
INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
|
||||
|
||||
// If the type list contains only one type, you can write that type
|
||||
// directly without Types<...>:
|
||||
// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int);
|
||||
|
||||
#endif // 0
|
||||
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
#include "gtest/internal/gtest-type-util.h"
|
||||
|
||||
// Implements typed tests.
|
||||
|
||||
#if GTEST_HAS_TYPED_TEST
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Expands to the name of the typedef for the type parameters of the
|
||||
// given test case.
|
||||
# define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_
|
||||
|
||||
// The 'Types' template argument below must have spaces around it
|
||||
// since some compilers may choke on '>>' when passing a template
|
||||
// instance (e.g. Types<int>)
|
||||
# define TYPED_TEST_CASE(CaseName, Types) \
|
||||
typedef ::testing::internal::TypeList< Types >::type \
|
||||
GTEST_TYPE_PARAMS_(CaseName)
|
||||
|
||||
# define TYPED_TEST(CaseName, TestName) \
|
||||
template <typename gtest_TypeParam_> \
|
||||
class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
|
||||
: public CaseName<gtest_TypeParam_> { \
|
||||
private: \
|
||||
typedef CaseName<gtest_TypeParam_> TestFixture; \
|
||||
typedef gtest_TypeParam_ TypeParam; \
|
||||
virtual void TestBody(); \
|
||||
}; \
|
||||
bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \
|
||||
::testing::internal::TypeParameterizedTest< \
|
||||
CaseName, \
|
||||
::testing::internal::TemplateSel< \
|
||||
GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \
|
||||
GTEST_TYPE_PARAMS_(CaseName)>::Register(\
|
||||
"", #CaseName, #TestName, 0); \
|
||||
template <typename gtest_TypeParam_> \
|
||||
void GTEST_TEST_CLASS_NAME_(CaseName, TestName)<gtest_TypeParam_>::TestBody()
|
||||
|
||||
#endif // GTEST_HAS_TYPED_TEST
|
||||
|
||||
// Implements type-parameterized tests.
|
||||
|
||||
#if GTEST_HAS_TYPED_TEST_P
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Expands to the namespace name that the type-parameterized tests for
|
||||
// the given type-parameterized test case are defined in. The exact
|
||||
// name of the namespace is subject to change without notice.
|
||||
# define GTEST_CASE_NAMESPACE_(TestCaseName) \
|
||||
gtest_case_##TestCaseName##_
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Expands to the name of the variable used to remember the names of
|
||||
// the defined tests in the given test case.
|
||||
# define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \
|
||||
gtest_typed_test_case_p_state_##TestCaseName##_
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY.
|
||||
//
|
||||
// Expands to the name of the variable used to remember the names of
|
||||
// the registered tests in the given test case.
|
||||
# define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \
|
||||
gtest_registered_test_names_##TestCaseName##_
|
||||
|
||||
// The variables defined in the type-parameterized test macros are
|
||||
// static as typically these macros are used in a .h file that can be
|
||||
// #included in multiple translation units linked together.
|
||||
# define TYPED_TEST_CASE_P(CaseName) \
|
||||
static ::testing::internal::TypedTestCasePState \
|
||||
GTEST_TYPED_TEST_CASE_P_STATE_(CaseName)
|
||||
|
||||
# define TYPED_TEST_P(CaseName, TestName) \
|
||||
namespace GTEST_CASE_NAMESPACE_(CaseName) { \
|
||||
template <typename gtest_TypeParam_> \
|
||||
class TestName : public CaseName<gtest_TypeParam_> { \
|
||||
private: \
|
||||
typedef CaseName<gtest_TypeParam_> TestFixture; \
|
||||
typedef gtest_TypeParam_ TypeParam; \
|
||||
virtual void TestBody(); \
|
||||
}; \
|
||||
static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \
|
||||
GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\
|
||||
__FILE__, __LINE__, #CaseName, #TestName); \
|
||||
} \
|
||||
template <typename gtest_TypeParam_> \
|
||||
void GTEST_CASE_NAMESPACE_(CaseName)::TestName<gtest_TypeParam_>::TestBody()
|
||||
|
||||
# define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \
|
||||
namespace GTEST_CASE_NAMESPACE_(CaseName) { \
|
||||
typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \
|
||||
} \
|
||||
static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \
|
||||
GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\
|
||||
__FILE__, __LINE__, #__VA_ARGS__)
|
||||
|
||||
// The 'Types' template argument below must have spaces around it
|
||||
// since some compilers may choke on '>>' when passing a template
|
||||
// instance (e.g. Types<int>)
|
||||
# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \
|
||||
bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \
|
||||
::testing::internal::TypeParameterizedTestCase<CaseName, \
|
||||
GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \
|
||||
::testing::internal::TypeList< Types >::type>::Register(\
|
||||
#Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName))
|
||||
|
||||
#endif // GTEST_HAS_TYPED_TEST_P
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
|
2155
thirdparty/gtest/include/gtest/gtest.h
vendored
Normal file
2155
thirdparty/gtest/include/gtest/gtest.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
358
thirdparty/gtest/include/gtest/gtest_pred_impl.h
vendored
Normal file
358
thirdparty/gtest/include/gtest/gtest_pred_impl.h
vendored
Normal file
@ -0,0 +1,358 @@
|
||||
// Copyright 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// This file is AUTOMATICALLY GENERATED on 09/24/2010 by command
|
||||
// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND!
|
||||
//
|
||||
// Implements a family of generic predicate assertion macros.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
|
||||
|
||||
// Makes sure this header is not included before gtest.h.
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
|
||||
# error Do not include gtest_pred_impl.h directly. Include gtest.h instead.
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_H_
|
||||
|
||||
// This header implements a family of generic predicate assertion
|
||||
// macros:
|
||||
//
|
||||
// ASSERT_PRED_FORMAT1(pred_format, v1)
|
||||
// ASSERT_PRED_FORMAT2(pred_format, v1, v2)
|
||||
// ...
|
||||
//
|
||||
// where pred_format is a function or functor that takes n (in the
|
||||
// case of ASSERT_PRED_FORMATn) values and their source expression
|
||||
// text, and returns a testing::AssertionResult. See the definition
|
||||
// of ASSERT_EQ in gtest.h for an example.
|
||||
//
|
||||
// If you don't care about formatting, you can use the more
|
||||
// restrictive version:
|
||||
//
|
||||
// ASSERT_PRED1(pred, v1)
|
||||
// ASSERT_PRED2(pred, v1, v2)
|
||||
// ...
|
||||
//
|
||||
// where pred is an n-ary function or functor that returns bool,
|
||||
// and the values v1, v2, ..., must support the << operator for
|
||||
// streaming to std::ostream.
|
||||
//
|
||||
// We also define the EXPECT_* variations.
|
||||
//
|
||||
// For now we only support predicates whose arity is at most 5.
|
||||
// Please email googletestframework@googlegroups.com if you need
|
||||
// support for higher arities.
|
||||
|
||||
// GTEST_ASSERT_ is the basic statement to which all of the assertions
|
||||
// in this file reduce. Don't use this in your code.
|
||||
|
||||
#define GTEST_ASSERT_(expression, on_failure) \
|
||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||
if (const ::testing::AssertionResult gtest_ar = (expression)) \
|
||||
; \
|
||||
else \
|
||||
on_failure(gtest_ar.failure_message())
|
||||
|
||||
|
||||
// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use
|
||||
// this in your code.
|
||||
template <typename Pred,
|
||||
typename T1>
|
||||
AssertionResult AssertPred1Helper(const char* pred_text,
|
||||
const char* e1,
|
||||
Pred pred,
|
||||
const T1& v1) {
|
||||
if (pred(v1)) return AssertionSuccess();
|
||||
|
||||
return AssertionFailure() << pred_text << "("
|
||||
<< e1 << ") evaluates to false, where"
|
||||
<< "\n" << e1 << " evaluates to " << v1;
|
||||
}
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1.
|
||||
// Don't use this in your code.
|
||||
#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\
|
||||
GTEST_ASSERT_(pred_format(#v1, v1),\
|
||||
on_failure)
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use
|
||||
// this in your code.
|
||||
#define GTEST_PRED1_(pred, v1, on_failure)\
|
||||
GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \
|
||||
#v1, \
|
||||
pred, \
|
||||
v1), on_failure)
|
||||
|
||||
// Unary predicate assertion macros.
|
||||
#define EXPECT_PRED_FORMAT1(pred_format, v1) \
|
||||
GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_)
|
||||
#define EXPECT_PRED1(pred, v1) \
|
||||
GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_)
|
||||
#define ASSERT_PRED_FORMAT1(pred_format, v1) \
|
||||
GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_)
|
||||
#define ASSERT_PRED1(pred, v1) \
|
||||
GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_)
|
||||
|
||||
|
||||
|
||||
// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use
|
||||
// this in your code.
|
||||
template <typename Pred,
|
||||
typename T1,
|
||||
typename T2>
|
||||
AssertionResult AssertPred2Helper(const char* pred_text,
|
||||
const char* e1,
|
||||
const char* e2,
|
||||
Pred pred,
|
||||
const T1& v1,
|
||||
const T2& v2) {
|
||||
if (pred(v1, v2)) return AssertionSuccess();
|
||||
|
||||
return AssertionFailure() << pred_text << "("
|
||||
<< e1 << ", "
|
||||
<< e2 << ") evaluates to false, where"
|
||||
<< "\n" << e1 << " evaluates to " << v1
|
||||
<< "\n" << e2 << " evaluates to " << v2;
|
||||
}
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2.
|
||||
// Don't use this in your code.
|
||||
#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\
|
||||
GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2),\
|
||||
on_failure)
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use
|
||||
// this in your code.
|
||||
#define GTEST_PRED2_(pred, v1, v2, on_failure)\
|
||||
GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \
|
||||
#v1, \
|
||||
#v2, \
|
||||
pred, \
|
||||
v1, \
|
||||
v2), on_failure)
|
||||
|
||||
// Binary predicate assertion macros.
|
||||
#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \
|
||||
GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
|
||||
#define EXPECT_PRED2(pred, v1, v2) \
|
||||
GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_)
|
||||
#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \
|
||||
GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_)
|
||||
#define ASSERT_PRED2(pred, v1, v2) \
|
||||
GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_)
|
||||
|
||||
|
||||
|
||||
// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use
|
||||
// this in your code.
|
||||
template <typename Pred,
|
||||
typename T1,
|
||||
typename T2,
|
||||
typename T3>
|
||||
AssertionResult AssertPred3Helper(const char* pred_text,
|
||||
const char* e1,
|
||||
const char* e2,
|
||||
const char* e3,
|
||||
Pred pred,
|
||||
const T1& v1,
|
||||
const T2& v2,
|
||||
const T3& v3) {
|
||||
if (pred(v1, v2, v3)) return AssertionSuccess();
|
||||
|
||||
return AssertionFailure() << pred_text << "("
|
||||
<< e1 << ", "
|
||||
<< e2 << ", "
|
||||
<< e3 << ") evaluates to false, where"
|
||||
<< "\n" << e1 << " evaluates to " << v1
|
||||
<< "\n" << e2 << " evaluates to " << v2
|
||||
<< "\n" << e3 << " evaluates to " << v3;
|
||||
}
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3.
|
||||
// Don't use this in your code.
|
||||
#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\
|
||||
GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3),\
|
||||
on_failure)
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use
|
||||
// this in your code.
|
||||
#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\
|
||||
GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \
|
||||
#v1, \
|
||||
#v2, \
|
||||
#v3, \
|
||||
pred, \
|
||||
v1, \
|
||||
v2, \
|
||||
v3), on_failure)
|
||||
|
||||
// Ternary predicate assertion macros.
|
||||
#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \
|
||||
GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
|
||||
#define EXPECT_PRED3(pred, v1, v2, v3) \
|
||||
GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
|
||||
#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \
|
||||
GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_)
|
||||
#define ASSERT_PRED3(pred, v1, v2, v3) \
|
||||
GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_)
|
||||
|
||||
|
||||
|
||||
// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use
|
||||
// this in your code.
|
||||
template <typename Pred,
|
||||
typename T1,
|
||||
typename T2,
|
||||
typename T3,
|
||||
typename T4>
|
||||
AssertionResult AssertPred4Helper(const char* pred_text,
|
||||
const char* e1,
|
||||
const char* e2,
|
||||
const char* e3,
|
||||
const char* e4,
|
||||
Pred pred,
|
||||
const T1& v1,
|
||||
const T2& v2,
|
||||
const T3& v3,
|
||||
const T4& v4) {
|
||||
if (pred(v1, v2, v3, v4)) return AssertionSuccess();
|
||||
|
||||
return AssertionFailure() << pred_text << "("
|
||||
<< e1 << ", "
|
||||
<< e2 << ", "
|
||||
<< e3 << ", "
|
||||
<< e4 << ") evaluates to false, where"
|
||||
<< "\n" << e1 << " evaluates to " << v1
|
||||
<< "\n" << e2 << " evaluates to " << v2
|
||||
<< "\n" << e3 << " evaluates to " << v3
|
||||
<< "\n" << e4 << " evaluates to " << v4;
|
||||
}
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4.
|
||||
// Don't use this in your code.
|
||||
#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\
|
||||
GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4),\
|
||||
on_failure)
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use
|
||||
// this in your code.
|
||||
#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\
|
||||
GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \
|
||||
#v1, \
|
||||
#v2, \
|
||||
#v3, \
|
||||
#v4, \
|
||||
pred, \
|
||||
v1, \
|
||||
v2, \
|
||||
v3, \
|
||||
v4), on_failure)
|
||||
|
||||
// 4-ary predicate assertion macros.
|
||||
#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
|
||||
GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
|
||||
#define EXPECT_PRED4(pred, v1, v2, v3, v4) \
|
||||
GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
|
||||
#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
|
||||
GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
|
||||
#define ASSERT_PRED4(pred, v1, v2, v3, v4) \
|
||||
GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
|
||||
|
||||
|
||||
|
||||
// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use
|
||||
// this in your code.
|
||||
template <typename Pred,
|
||||
typename T1,
|
||||
typename T2,
|
||||
typename T3,
|
||||
typename T4,
|
||||
typename T5>
|
||||
AssertionResult AssertPred5Helper(const char* pred_text,
|
||||
const char* e1,
|
||||
const char* e2,
|
||||
const char* e3,
|
||||
const char* e4,
|
||||
const char* e5,
|
||||
Pred pred,
|
||||
const T1& v1,
|
||||
const T2& v2,
|
||||
const T3& v3,
|
||||
const T4& v4,
|
||||
const T5& v5) {
|
||||
if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess();
|
||||
|
||||
return AssertionFailure() << pred_text << "("
|
||||
<< e1 << ", "
|
||||
<< e2 << ", "
|
||||
<< e3 << ", "
|
||||
<< e4 << ", "
|
||||
<< e5 << ") evaluates to false, where"
|
||||
<< "\n" << e1 << " evaluates to " << v1
|
||||
<< "\n" << e2 << " evaluates to " << v2
|
||||
<< "\n" << e3 << " evaluates to " << v3
|
||||
<< "\n" << e4 << " evaluates to " << v4
|
||||
<< "\n" << e5 << " evaluates to " << v5;
|
||||
}
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5.
|
||||
// Don't use this in your code.
|
||||
#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\
|
||||
GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5),\
|
||||
on_failure)
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use
|
||||
// this in your code.
|
||||
#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\
|
||||
GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \
|
||||
#v1, \
|
||||
#v2, \
|
||||
#v3, \
|
||||
#v4, \
|
||||
#v5, \
|
||||
pred, \
|
||||
v1, \
|
||||
v2, \
|
||||
v3, \
|
||||
v4, \
|
||||
v5), on_failure)
|
||||
|
||||
// 5-ary predicate assertion macros.
|
||||
#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
|
||||
GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
|
||||
#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \
|
||||
GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
|
||||
#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
|
||||
GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
|
||||
#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \
|
||||
GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
|
||||
|
||||
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
|
58
thirdparty/gtest/include/gtest/gtest_prod.h
vendored
Normal file
58
thirdparty/gtest/include/gtest/gtest_prod.h
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
//
|
||||
// Google C++ Testing Framework definitions useful in production code.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_
|
||||
|
||||
// When you need to test the private or protected members of a class,
|
||||
// use the FRIEND_TEST macro to declare your tests as friends of the
|
||||
// class. For example:
|
||||
//
|
||||
// class MyClass {
|
||||
// private:
|
||||
// void MyMethod();
|
||||
// FRIEND_TEST(MyClassTest, MyMethod);
|
||||
// };
|
||||
//
|
||||
// class MyClassTest : public testing::Test {
|
||||
// // ...
|
||||
// };
|
||||
//
|
||||
// TEST_F(MyClassTest, MyMethod) {
|
||||
// // Can call MyClass::MyMethod() here.
|
||||
// }
|
||||
|
||||
#define FRIEND_TEST(test_case_name, test_name)\
|
||||
friend class test_case_name##_##test_name##_Test
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_
|
308
thirdparty/gtest/include/gtest/internal/gtest-death-test-internal.h
vendored
Normal file
308
thirdparty/gtest/include/gtest/internal/gtest-death-test-internal.h
vendored
Normal file
@ -0,0 +1,308 @@
|
||||
// Copyright 2005, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
|
||||
//
|
||||
// The Google C++ Testing Framework (Google Test)
|
||||
//
|
||||
// This header file defines internal utilities needed for implementing
|
||||
// death tests. They are subject to change without notice.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
|
||||
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
GTEST_DECLARE_string_(internal_run_death_test);
|
||||
|
||||
// Names of the flags (needed for parsing Google Test flags).
|
||||
const char kDeathTestStyleFlag[] = "death_test_style";
|
||||
const char kDeathTestUseFork[] = "death_test_use_fork";
|
||||
const char kInternalRunDeathTestFlag[] = "internal_run_death_test";
|
||||
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
|
||||
// DeathTest is a class that hides much of the complexity of the
|
||||
// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method
|
||||
// returns a concrete class that depends on the prevailing death test
|
||||
// style, as defined by the --gtest_death_test_style and/or
|
||||
// --gtest_internal_run_death_test flags.
|
||||
|
||||
// In describing the results of death tests, these terms are used with
|
||||
// the corresponding definitions:
|
||||
//
|
||||
// exit status: The integer exit information in the format specified
|
||||
// by wait(2)
|
||||
// exit code: The integer code passed to exit(3), _exit(2), or
|
||||
// returned from main()
|
||||
class GTEST_API_ DeathTest {
|
||||
public:
|
||||
// Create returns false if there was an error determining the
|
||||
// appropriate action to take for the current death test; for example,
|
||||
// if the gtest_death_test_style flag is set to an invalid value.
|
||||
// The LastMessage method will return a more detailed message in that
|
||||
// case. Otherwise, the DeathTest pointer pointed to by the "test"
|
||||
// argument is set. If the death test should be skipped, the pointer
|
||||
// is set to NULL; otherwise, it is set to the address of a new concrete
|
||||
// DeathTest object that controls the execution of the current test.
|
||||
static bool Create(const char* statement, const RE* regex,
|
||||
const char* file, int line, DeathTest** test);
|
||||
DeathTest();
|
||||
virtual ~DeathTest() { }
|
||||
|
||||
// A helper class that aborts a death test when it's deleted.
|
||||
class ReturnSentinel {
|
||||
public:
|
||||
explicit ReturnSentinel(DeathTest* test) : test_(test) { }
|
||||
~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); }
|
||||
private:
|
||||
DeathTest* const test_;
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel);
|
||||
} GTEST_ATTRIBUTE_UNUSED_;
|
||||
|
||||
// An enumeration of possible roles that may be taken when a death
|
||||
// test is encountered. EXECUTE means that the death test logic should
|
||||
// be executed immediately. OVERSEE means that the program should prepare
|
||||
// the appropriate environment for a child process to execute the death
|
||||
// test, then wait for it to complete.
|
||||
enum TestRole { OVERSEE_TEST, EXECUTE_TEST };
|
||||
|
||||
// An enumeration of the three reasons that a test might be aborted.
|
||||
enum AbortReason {
|
||||
TEST_ENCOUNTERED_RETURN_STATEMENT,
|
||||
TEST_THREW_EXCEPTION,
|
||||
TEST_DID_NOT_DIE
|
||||
};
|
||||
|
||||
// Assumes one of the above roles.
|
||||
virtual TestRole AssumeRole() = 0;
|
||||
|
||||
// Waits for the death test to finish and returns its status.
|
||||
virtual int Wait() = 0;
|
||||
|
||||
// Returns true if the death test passed; that is, the test process
|
||||
// exited during the test, its exit status matches a user-supplied
|
||||
// predicate, and its stderr output matches a user-supplied regular
|
||||
// expression.
|
||||
// The user-supplied predicate may be a macro expression rather
|
||||
// than a function pointer or functor, or else Wait and Passed could
|
||||
// be combined.
|
||||
virtual bool Passed(bool exit_status_ok) = 0;
|
||||
|
||||
// Signals that the death test did not die as expected.
|
||||
virtual void Abort(AbortReason reason) = 0;
|
||||
|
||||
// Returns a human-readable outcome message regarding the outcome of
|
||||
// the last death test.
|
||||
static const char* LastMessage();
|
||||
|
||||
static void set_last_death_test_message(const String& message);
|
||||
|
||||
private:
|
||||
// A string containing a description of the outcome of the last death test.
|
||||
static String last_death_test_message_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest);
|
||||
};
|
||||
|
||||
// Factory interface for death tests. May be mocked out for testing.
|
||||
class DeathTestFactory {
|
||||
public:
|
||||
virtual ~DeathTestFactory() { }
|
||||
virtual bool Create(const char* statement, const RE* regex,
|
||||
const char* file, int line, DeathTest** test) = 0;
|
||||
};
|
||||
|
||||
// A concrete DeathTestFactory implementation for normal use.
|
||||
class DefaultDeathTestFactory : public DeathTestFactory {
|
||||
public:
|
||||
virtual bool Create(const char* statement, const RE* regex,
|
||||
const char* file, int line, DeathTest** test);
|
||||
};
|
||||
|
||||
// Returns true if exit_status describes a process that was terminated
|
||||
// by a signal, or exited normally with a nonzero exit code.
|
||||
GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
|
||||
|
||||
// Traps C++ exceptions escaping statement and reports them as test
|
||||
// failures. Note that trapping SEH exceptions is not implemented here.
|
||||
# if GTEST_HAS_EXCEPTIONS
|
||||
# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \
|
||||
try { \
|
||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
|
||||
} catch (const ::std::exception& gtest_exception) { \
|
||||
fprintf(\
|
||||
stderr, \
|
||||
"\n%s: Caught std::exception-derived exception escaping the " \
|
||||
"death test statement. Exception message: %s\n", \
|
||||
::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \
|
||||
gtest_exception.what()); \
|
||||
fflush(stderr); \
|
||||
death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \
|
||||
} catch (...) { \
|
||||
death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \
|
||||
}
|
||||
|
||||
# else
|
||||
# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \
|
||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
|
||||
|
||||
# endif
|
||||
|
||||
// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*,
|
||||
// ASSERT_EXIT*, and EXPECT_EXIT*.
|
||||
# define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \
|
||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||
if (::testing::internal::AlwaysTrue()) { \
|
||||
const ::testing::internal::RE& gtest_regex = (regex); \
|
||||
::testing::internal::DeathTest* gtest_dt; \
|
||||
if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \
|
||||
__FILE__, __LINE__, >est_dt)) { \
|
||||
goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
|
||||
} \
|
||||
if (gtest_dt != NULL) { \
|
||||
::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \
|
||||
gtest_dt_ptr(gtest_dt); \
|
||||
switch (gtest_dt->AssumeRole()) { \
|
||||
case ::testing::internal::DeathTest::OVERSEE_TEST: \
|
||||
if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \
|
||||
goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
|
||||
} \
|
||||
break; \
|
||||
case ::testing::internal::DeathTest::EXECUTE_TEST: { \
|
||||
::testing::internal::DeathTest::ReturnSentinel \
|
||||
gtest_sentinel(gtest_dt); \
|
||||
GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \
|
||||
gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \
|
||||
break; \
|
||||
} \
|
||||
default: \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} else \
|
||||
GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \
|
||||
fail(::testing::internal::DeathTest::LastMessage())
|
||||
// The symbol "fail" here expands to something into which a message
|
||||
// can be streamed.
|
||||
|
||||
// A class representing the parsed contents of the
|
||||
// --gtest_internal_run_death_test flag, as it existed when
|
||||
// RUN_ALL_TESTS was called.
|
||||
class InternalRunDeathTestFlag {
|
||||
public:
|
||||
InternalRunDeathTestFlag(const String& a_file,
|
||||
int a_line,
|
||||
int an_index,
|
||||
int a_write_fd)
|
||||
: file_(a_file), line_(a_line), index_(an_index),
|
||||
write_fd_(a_write_fd) {}
|
||||
|
||||
~InternalRunDeathTestFlag() {
|
||||
if (write_fd_ >= 0)
|
||||
posix::Close(write_fd_);
|
||||
}
|
||||
|
||||
String file() const { return file_; }
|
||||
int line() const { return line_; }
|
||||
int index() const { return index_; }
|
||||
int write_fd() const { return write_fd_; }
|
||||
|
||||
private:
|
||||
String file_;
|
||||
int line_;
|
||||
int index_;
|
||||
int write_fd_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag);
|
||||
};
|
||||
|
||||
// Returns a newly created InternalRunDeathTestFlag object with fields
|
||||
// initialized from the GTEST_FLAG(internal_run_death_test) flag if
|
||||
// the flag is specified; otherwise returns NULL.
|
||||
InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag();
|
||||
|
||||
#else // GTEST_HAS_DEATH_TEST
|
||||
|
||||
// This macro is used for implementing macros such as
|
||||
// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where
|
||||
// death tests are not supported. Those macros must compile on such systems
|
||||
// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on
|
||||
// systems that support death tests. This allows one to write such a macro
|
||||
// on a system that does not support death tests and be sure that it will
|
||||
// compile on a death-test supporting system.
|
||||
//
|
||||
// Parameters:
|
||||
// statement - A statement that a macro such as EXPECT_DEATH would test
|
||||
// for program termination. This macro has to make sure this
|
||||
// statement is compiled but not executed, to ensure that
|
||||
// EXPECT_DEATH_IF_SUPPORTED compiles with a certain
|
||||
// parameter iff EXPECT_DEATH compiles with it.
|
||||
// regex - A regex that a macro such as EXPECT_DEATH would use to test
|
||||
// the output of statement. This parameter has to be
|
||||
// compiled but not evaluated by this macro, to ensure that
|
||||
// this macro only accepts expressions that a macro such as
|
||||
// EXPECT_DEATH would accept.
|
||||
// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED
|
||||
// and a return statement for ASSERT_DEATH_IF_SUPPORTED.
|
||||
// This ensures that ASSERT_DEATH_IF_SUPPORTED will not
|
||||
// compile inside functions where ASSERT_DEATH doesn't
|
||||
// compile.
|
||||
//
|
||||
// The branch that has an always false condition is used to ensure that
|
||||
// statement and regex are compiled (and thus syntactically correct) but
|
||||
// never executed. The unreachable code macro protects the terminator
|
||||
// statement from generating an 'unreachable code' warning in case
|
||||
// statement unconditionally returns or throws. The Message constructor at
|
||||
// the end allows the syntax of streaming additional messages into the
|
||||
// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH.
|
||||
# define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \
|
||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||
if (::testing::internal::AlwaysTrue()) { \
|
||||
GTEST_LOG_(WARNING) \
|
||||
<< "Death tests are not supported on this platform.\n" \
|
||||
<< "Statement '" #statement "' cannot be verified."; \
|
||||
} else if (::testing::internal::AlwaysFalse()) { \
|
||||
::testing::internal::RE::PartialMatch(".*", (regex)); \
|
||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
|
||||
terminator; \
|
||||
} else \
|
||||
::testing::Message()
|
||||
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
|
210
thirdparty/gtest/include/gtest/internal/gtest-filepath.h
vendored
Normal file
210
thirdparty/gtest/include/gtest/internal/gtest-filepath.h
vendored
Normal file
@ -0,0 +1,210 @@
|
||||
// Copyright 2008, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: keith.ray@gmail.com (Keith Ray)
|
||||
//
|
||||
// Google Test filepath utilities
|
||||
//
|
||||
// This header file declares classes and functions used internally by
|
||||
// Google Test. They are subject to change without notice.
|
||||
//
|
||||
// This file is #included in <gtest/internal/gtest-internal.h>.
|
||||
// Do not include this header file separately!
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
|
||||
|
||||
#include "gtest/internal/gtest-string.h"
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
// FilePath - a class for file and directory pathname manipulation which
|
||||
// handles platform-specific conventions (like the pathname separator).
|
||||
// Used for helper functions for naming files in a directory for xml output.
|
||||
// Except for Set methods, all methods are const or static, which provides an
|
||||
// "immutable value object" -- useful for peace of mind.
|
||||
// A FilePath with a value ending in a path separator ("like/this/") represents
|
||||
// a directory, otherwise it is assumed to represent a file. In either case,
|
||||
// it may or may not represent an actual file or directory in the file system.
|
||||
// Names are NOT checked for syntax correctness -- no checking for illegal
|
||||
// characters, malformed paths, etc.
|
||||
|
||||
class GTEST_API_ FilePath {
|
||||
public:
|
||||
FilePath() : pathname_("") { }
|
||||
FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { }
|
||||
|
||||
explicit FilePath(const char* pathname) : pathname_(pathname) {
|
||||
Normalize();
|
||||
}
|
||||
|
||||
explicit FilePath(const String& pathname) : pathname_(pathname) {
|
||||
Normalize();
|
||||
}
|
||||
|
||||
FilePath& operator=(const FilePath& rhs) {
|
||||
Set(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Set(const FilePath& rhs) {
|
||||
pathname_ = rhs.pathname_;
|
||||
}
|
||||
|
||||
String ToString() const { return pathname_; }
|
||||
const char* c_str() const { return pathname_.c_str(); }
|
||||
|
||||
// Returns the current working directory, or "" if unsuccessful.
|
||||
static FilePath GetCurrentDir();
|
||||
|
||||
// Given directory = "dir", base_name = "test", number = 0,
|
||||
// extension = "xml", returns "dir/test.xml". If number is greater
|
||||
// than zero (e.g., 12), returns "dir/test_12.xml".
|
||||
// On Windows platform, uses \ as the separator rather than /.
|
||||
static FilePath MakeFileName(const FilePath& directory,
|
||||
const FilePath& base_name,
|
||||
int number,
|
||||
const char* extension);
|
||||
|
||||
// Given directory = "dir", relative_path = "test.xml",
|
||||
// returns "dir/test.xml".
|
||||
// On Windows, uses \ as the separator rather than /.
|
||||
static FilePath ConcatPaths(const FilePath& directory,
|
||||
const FilePath& relative_path);
|
||||
|
||||
// Returns a pathname for a file that does not currently exist. The pathname
|
||||
// will be directory/base_name.extension or
|
||||
// directory/base_name_<number>.extension if directory/base_name.extension
|
||||
// already exists. The number will be incremented until a pathname is found
|
||||
// that does not already exist.
|
||||
// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
|
||||
// There could be a race condition if two or more processes are calling this
|
||||
// function at the same time -- they could both pick the same filename.
|
||||
static FilePath GenerateUniqueFileName(const FilePath& directory,
|
||||
const FilePath& base_name,
|
||||
const char* extension);
|
||||
|
||||
// Returns true iff the path is NULL or "".
|
||||
bool IsEmpty() const { return c_str() == NULL || *c_str() == '\0'; }
|
||||
|
||||
// If input name has a trailing separator character, removes it and returns
|
||||
// the name, otherwise return the name string unmodified.
|
||||
// On Windows platform, uses \ as the separator, other platforms use /.
|
||||
FilePath RemoveTrailingPathSeparator() const;
|
||||
|
||||
// Returns a copy of the FilePath with the directory part removed.
|
||||
// Example: FilePath("path/to/file").RemoveDirectoryName() returns
|
||||
// FilePath("file"). If there is no directory part ("just_a_file"), it returns
|
||||
// the FilePath unmodified. If there is no file part ("just_a_dir/") it
|
||||
// returns an empty FilePath ("").
|
||||
// On Windows platform, '\' is the path separator, otherwise it is '/'.
|
||||
FilePath RemoveDirectoryName() const;
|
||||
|
||||
// RemoveFileName returns the directory path with the filename removed.
|
||||
// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
|
||||
// If the FilePath is "a_file" or "/a_file", RemoveFileName returns
|
||||
// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
|
||||
// not have a file, like "just/a/dir/", it returns the FilePath unmodified.
|
||||
// On Windows platform, '\' is the path separator, otherwise it is '/'.
|
||||
FilePath RemoveFileName() const;
|
||||
|
||||
// Returns a copy of the FilePath with the case-insensitive extension removed.
|
||||
// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
|
||||
// FilePath("dir/file"). If a case-insensitive extension is not
|
||||
// found, returns a copy of the original FilePath.
|
||||
FilePath RemoveExtension(const char* extension) const;
|
||||
|
||||
// Creates directories so that path exists. Returns true if successful or if
|
||||
// the directories already exist; returns false if unable to create
|
||||
// directories for any reason. Will also return false if the FilePath does
|
||||
// not represent a directory (that is, it doesn't end with a path separator).
|
||||
bool CreateDirectoriesRecursively() const;
|
||||
|
||||
// Create the directory so that path exists. Returns true if successful or
|
||||
// if the directory already exists; returns false if unable to create the
|
||||
// directory for any reason, including if the parent directory does not
|
||||
// exist. Not named "CreateDirectory" because that's a macro on Windows.
|
||||
bool CreateFolder() const;
|
||||
|
||||
// Returns true if FilePath describes something in the file-system,
|
||||
// either a file, directory, or whatever, and that something exists.
|
||||
bool FileOrDirectoryExists() const;
|
||||
|
||||
// Returns true if pathname describes a directory in the file-system
|
||||
// that exists.
|
||||
bool DirectoryExists() const;
|
||||
|
||||
// Returns true if FilePath ends with a path separator, which indicates that
|
||||
// it is intended to represent a directory. Returns false otherwise.
|
||||
// This does NOT check that a directory (or file) actually exists.
|
||||
bool IsDirectory() const;
|
||||
|
||||
// Returns true if pathname describes a root directory. (Windows has one
|
||||
// root directory per disk drive.)
|
||||
bool IsRootDirectory() const;
|
||||
|
||||
// Returns true if pathname describes an absolute path.
|
||||
bool IsAbsolutePath() const;
|
||||
|
||||
private:
|
||||
// Replaces multiple consecutive separators with a single separator.
|
||||
// For example, "bar///foo" becomes "bar/foo". Does not eliminate other
|
||||
// redundancies that might be in a pathname involving "." or "..".
|
||||
//
|
||||
// A pathname with multiple consecutive separators may occur either through
|
||||
// user error or as a result of some scripts or APIs that generate a pathname
|
||||
// with a trailing separator. On other platforms the same API or script
|
||||
// may NOT generate a pathname with a trailing "/". Then elsewhere that
|
||||
// pathname may have another "/" and pathname components added to it,
|
||||
// without checking for the separator already being there.
|
||||
// The script language and operating system may allow paths like "foo//bar"
|
||||
// but some of the functions in FilePath will not handle that correctly. In
|
||||
// particular, RemoveTrailingPathSeparator() only removes one separator, and
|
||||
// it is called in CreateDirectoriesRecursively() assuming that it will change
|
||||
// a pathname from directory syntax (trailing separator) to filename syntax.
|
||||
//
|
||||
// On Windows this method also replaces the alternate path separator '/' with
|
||||
// the primary path separator '\\', so that for example "bar\\/\\foo" becomes
|
||||
// "bar\\foo".
|
||||
|
||||
void Normalize();
|
||||
|
||||
// Returns a pointer to the last occurence of a valid path separator in
|
||||
// the FilePath. On Windows, for example, both '/' and '\' are valid path
|
||||
// separators. Returns NULL if no path separator was found.
|
||||
const char* FindLastPathSeparator() const;
|
||||
|
||||
String pathname_;
|
||||
}; // class FilePath
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
|
1226
thirdparty/gtest/include/gtest/internal/gtest-internal.h
vendored
Normal file
1226
thirdparty/gtest/include/gtest/internal/gtest-internal.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
233
thirdparty/gtest/include/gtest/internal/gtest-linked_ptr.h
vendored
Normal file
233
thirdparty/gtest/include/gtest/internal/gtest-linked_ptr.h
vendored
Normal file
@ -0,0 +1,233 @@
|
||||
// Copyright 2003 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Authors: Dan Egnor (egnor@google.com)
|
||||
//
|
||||
// A "smart" pointer type with reference tracking. Every pointer to a
|
||||
// particular object is kept on a circular linked list. When the last pointer
|
||||
// to an object is destroyed or reassigned, the object is deleted.
|
||||
//
|
||||
// Used properly, this deletes the object when the last reference goes away.
|
||||
// There are several caveats:
|
||||
// - Like all reference counting schemes, cycles lead to leaks.
|
||||
// - Each smart pointer is actually two pointers (8 bytes instead of 4).
|
||||
// - Every time a pointer is assigned, the entire list of pointers to that
|
||||
// object is traversed. This class is therefore NOT SUITABLE when there
|
||||
// will often be more than two or three pointers to a particular object.
|
||||
// - References are only tracked as long as linked_ptr<> objects are copied.
|
||||
// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS
|
||||
// will happen (double deletion).
|
||||
//
|
||||
// A good use of this class is storing object references in STL containers.
|
||||
// You can safely put linked_ptr<> in a vector<>.
|
||||
// Other uses may not be as good.
|
||||
//
|
||||
// Note: If you use an incomplete type with linked_ptr<>, the class
|
||||
// *containing* linked_ptr<> must have a constructor and destructor (even
|
||||
// if they do nothing!).
|
||||
//
|
||||
// Bill Gibbons suggested we use something like this.
|
||||
//
|
||||
// Thread Safety:
|
||||
// Unlike other linked_ptr implementations, in this implementation
|
||||
// a linked_ptr object is thread-safe in the sense that:
|
||||
// - it's safe to copy linked_ptr objects concurrently,
|
||||
// - it's safe to copy *from* a linked_ptr and read its underlying
|
||||
// raw pointer (e.g. via get()) concurrently, and
|
||||
// - it's safe to write to two linked_ptrs that point to the same
|
||||
// shared object concurrently.
|
||||
// TODO(wan@google.com): rename this to safe_linked_ptr to avoid
|
||||
// confusion with normal linked_ptr.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
// Protects copying of all linked_ptr objects.
|
||||
GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex);
|
||||
|
||||
// This is used internally by all instances of linked_ptr<>. It needs to be
|
||||
// a non-template class because different types of linked_ptr<> can refer to
|
||||
// the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)).
|
||||
// So, it needs to be possible for different types of linked_ptr to participate
|
||||
// in the same circular linked list, so we need a single class type here.
|
||||
//
|
||||
// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr<T>.
|
||||
class linked_ptr_internal {
|
||||
public:
|
||||
// Create a new circle that includes only this instance.
|
||||
void join_new() {
|
||||
next_ = this;
|
||||
}
|
||||
|
||||
// Many linked_ptr operations may change p.link_ for some linked_ptr
|
||||
// variable p in the same circle as this object. Therefore we need
|
||||
// to prevent two such operations from occurring concurrently.
|
||||
//
|
||||
// Note that different types of linked_ptr objects can coexist in a
|
||||
// circle (e.g. linked_ptr<Base>, linked_ptr<Derived1>, and
|
||||
// linked_ptr<Derived2>). Therefore we must use a single mutex to
|
||||
// protect all linked_ptr objects. This can create serious
|
||||
// contention in production code, but is acceptable in a testing
|
||||
// framework.
|
||||
|
||||
// Join an existing circle.
|
||||
// L < g_linked_ptr_mutex
|
||||
void join(linked_ptr_internal const* ptr) {
|
||||
MutexLock lock(&g_linked_ptr_mutex);
|
||||
|
||||
linked_ptr_internal const* p = ptr;
|
||||
while (p->next_ != ptr) p = p->next_;
|
||||
p->next_ = this;
|
||||
next_ = ptr;
|
||||
}
|
||||
|
||||
// Leave whatever circle we're part of. Returns true if we were the
|
||||
// last member of the circle. Once this is done, you can join() another.
|
||||
// L < g_linked_ptr_mutex
|
||||
bool depart() {
|
||||
MutexLock lock(&g_linked_ptr_mutex);
|
||||
|
||||
if (next_ == this) return true;
|
||||
linked_ptr_internal const* p = next_;
|
||||
while (p->next_ != this) p = p->next_;
|
||||
p->next_ = next_;
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable linked_ptr_internal const* next_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class linked_ptr {
|
||||
public:
|
||||
typedef T element_type;
|
||||
|
||||
// Take over ownership of a raw pointer. This should happen as soon as
|
||||
// possible after the object is created.
|
||||
explicit linked_ptr(T* ptr = NULL) { capture(ptr); }
|
||||
~linked_ptr() { depart(); }
|
||||
|
||||
// Copy an existing linked_ptr<>, adding ourselves to the list of references.
|
||||
template <typename U> linked_ptr(linked_ptr<U> const& ptr) { copy(&ptr); }
|
||||
linked_ptr(linked_ptr const& ptr) { // NOLINT
|
||||
assert(&ptr != this);
|
||||
copy(&ptr);
|
||||
}
|
||||
|
||||
// Assignment releases the old value and acquires the new.
|
||||
template <typename U> linked_ptr& operator=(linked_ptr<U> const& ptr) {
|
||||
depart();
|
||||
copy(&ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
linked_ptr& operator=(linked_ptr const& ptr) {
|
||||
if (&ptr != this) {
|
||||
depart();
|
||||
copy(&ptr);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Smart pointer members.
|
||||
void reset(T* ptr = NULL) {
|
||||
depart();
|
||||
capture(ptr);
|
||||
}
|
||||
T* get() const { return value_; }
|
||||
T* operator->() const { return value_; }
|
||||
T& operator*() const { return *value_; }
|
||||
|
||||
bool operator==(T* p) const { return value_ == p; }
|
||||
bool operator!=(T* p) const { return value_ != p; }
|
||||
template <typename U>
|
||||
bool operator==(linked_ptr<U> const& ptr) const {
|
||||
return value_ == ptr.get();
|
||||
}
|
||||
template <typename U>
|
||||
bool operator!=(linked_ptr<U> const& ptr) const {
|
||||
return value_ != ptr.get();
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename U>
|
||||
friend class linked_ptr;
|
||||
|
||||
T* value_;
|
||||
linked_ptr_internal link_;
|
||||
|
||||
void depart() {
|
||||
if (link_.depart()) delete value_;
|
||||
}
|
||||
|
||||
void capture(T* ptr) {
|
||||
value_ = ptr;
|
||||
link_.join_new();
|
||||
}
|
||||
|
||||
template <typename U> void copy(linked_ptr<U> const* ptr) {
|
||||
value_ = ptr->get();
|
||||
if (value_)
|
||||
link_.join(&ptr->link_);
|
||||
else
|
||||
link_.join_new();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> inline
|
||||
bool operator==(T* ptr, const linked_ptr<T>& x) {
|
||||
return ptr == x.get();
|
||||
}
|
||||
|
||||
template<typename T> inline
|
||||
bool operator!=(T* ptr, const linked_ptr<T>& x) {
|
||||
return ptr != x.get();
|
||||
}
|
||||
|
||||
// A function to convert T* into linked_ptr<T>
|
||||
// Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation
|
||||
// for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
|
||||
template <typename T>
|
||||
linked_ptr<T> make_linked_ptr(T* ptr) {
|
||||
return linked_ptr<T>(ptr);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
|
4822
thirdparty/gtest/include/gtest/internal/gtest-param-util-generated.h
vendored
Normal file
4822
thirdparty/gtest/include/gtest/internal/gtest-param-util-generated.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
301
thirdparty/gtest/include/gtest/internal/gtest-param-util-generated.h.pump
vendored
Normal file
301
thirdparty/gtest/include/gtest/internal/gtest-param-util-generated.h.pump
vendored
Normal file
@ -0,0 +1,301 @@
|
||||
$$ -*- mode: c++; -*-
|
||||
$var n = 50 $$ Maximum length of Values arguments we want to support.
|
||||
$var maxtuple = 10 $$ Maximum number of Combine arguments we want to support.
|
||||
// Copyright 2008 Google Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: vladl@google.com (Vlad Losev)
|
||||
|
||||
// Type and function utilities for implementing parameterized tests.
|
||||
// This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
|
||||
//
|
||||
// Currently Google Test supports at most $n arguments in Values,
|
||||
// and at most $maxtuple arguments in Combine. Please contact
|
||||
// googletestframework@googlegroups.com if you need more.
|
||||
// Please note that the number of arguments to Combine is limited
|
||||
// by the maximum arity of the implementation of tr1::tuple which is
|
||||
// currently set at $maxtuple.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
|
||||
|
||||
// scripts/fuse_gtest.py depends on gtest's own header being #included
|
||||
// *unconditionally*. Therefore these #includes cannot be moved
|
||||
// inside #if GTEST_HAS_PARAM_TEST.
|
||||
#include "gtest/internal/gtest-param-util.h"
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
#if GTEST_HAS_PARAM_TEST
|
||||
|
||||
namespace testing {
|
||||
|
||||
// Forward declarations of ValuesIn(), which is implemented in
|
||||
// include/gtest/gtest-param-test.h.
|
||||
template <typename ForwardIterator>
|
||||
internal::ParamGenerator<
|
||||
typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>
|
||||
ValuesIn(ForwardIterator begin, ForwardIterator end);
|
||||
|
||||
template <typename T, size_t N>
|
||||
internal::ParamGenerator<T> ValuesIn(const T (&array)[N]);
|
||||
|
||||
template <class Container>
|
||||
internal::ParamGenerator<typename Container::value_type> ValuesIn(
|
||||
const Container& container);
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Used in the Values() function to provide polymorphic capabilities.
|
||||
template <typename T1>
|
||||
class ValueArray1 {
|
||||
public:
|
||||
explicit ValueArray1(T1 v1) : v1_(v1) {}
|
||||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const { return ValuesIn(&v1_, &v1_ + 1); }
|
||||
|
||||
private:
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const ValueArray1& other);
|
||||
|
||||
const T1 v1_;
|
||||
};
|
||||
|
||||
$range i 2..n
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
|
||||
template <$for j, [[typename T$j]]>
|
||||
class ValueArray$i {
|
||||
public:
|
||||
ValueArray$i($for j, [[T$j v$j]]) : $for j, [[v$(j)_(v$j)]] {}
|
||||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {$for j, [[v$(j)_]]};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
private:
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const ValueArray$i& other);
|
||||
|
||||
$for j [[
|
||||
|
||||
const T$j v$(j)_;
|
||||
]]
|
||||
|
||||
};
|
||||
|
||||
]]
|
||||
|
||||
# if GTEST_HAS_COMBINE
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Generates values from the Cartesian product of values produced
|
||||
// by the argument generators.
|
||||
//
|
||||
$range i 2..maxtuple
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
$range k 2..i
|
||||
|
||||
template <$for j, [[typename T$j]]>
|
||||
class CartesianProductGenerator$i
|
||||
: public ParamGeneratorInterface< ::std::tr1::tuple<$for j, [[T$j]]> > {
|
||||
public:
|
||||
typedef ::std::tr1::tuple<$for j, [[T$j]]> ParamType;
|
||||
|
||||
CartesianProductGenerator$i($for j, [[const ParamGenerator<T$j>& g$j]])
|
||||
: $for j, [[g$(j)_(g$j)]] {}
|
||||
virtual ~CartesianProductGenerator$i() {}
|
||||
|
||||
virtual ParamIteratorInterface<ParamType>* Begin() const {
|
||||
return new Iterator(this, $for j, [[g$(j)_, g$(j)_.begin()]]);
|
||||
}
|
||||
virtual ParamIteratorInterface<ParamType>* End() const {
|
||||
return new Iterator(this, $for j, [[g$(j)_, g$(j)_.end()]]);
|
||||
}
|
||||
|
||||
private:
|
||||
class Iterator : public ParamIteratorInterface<ParamType> {
|
||||
public:
|
||||
Iterator(const ParamGeneratorInterface<ParamType>* base, $for j, [[
|
||||
|
||||
const ParamGenerator<T$j>& g$j,
|
||||
const typename ParamGenerator<T$j>::iterator& current$(j)]])
|
||||
: base_(base),
|
||||
$for j, [[
|
||||
|
||||
begin$(j)_(g$j.begin()), end$(j)_(g$j.end()), current$(j)_(current$j)
|
||||
]] {
|
||||
ComputeCurrentValue();
|
||||
}
|
||||
virtual ~Iterator() {}
|
||||
|
||||
virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
|
||||
return base_;
|
||||
}
|
||||
// Advance should not be called on beyond-of-range iterators
|
||||
// so no component iterators must be beyond end of range, either.
|
||||
virtual void Advance() {
|
||||
assert(!AtEnd());
|
||||
++current$(i)_;
|
||||
|
||||
$for k [[
|
||||
if (current$(i+2-k)_ == end$(i+2-k)_) {
|
||||
current$(i+2-k)_ = begin$(i+2-k)_;
|
||||
++current$(i+2-k-1)_;
|
||||
}
|
||||
|
||||
]]
|
||||
ComputeCurrentValue();
|
||||
}
|
||||
virtual ParamIteratorInterface<ParamType>* Clone() const {
|
||||
return new Iterator(*this);
|
||||
}
|
||||
virtual const ParamType* Current() const { return ¤t_value_; }
|
||||
virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
|
||||
// Having the same base generator guarantees that the other
|
||||
// iterator is of the same type and we can downcast.
|
||||
GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
|
||||
<< "The program attempted to compare iterators "
|
||||
<< "from different generators." << std::endl;
|
||||
const Iterator* typed_other =
|
||||
CheckedDowncastToActualType<const Iterator>(&other);
|
||||
// We must report iterators equal if they both point beyond their
|
||||
// respective ranges. That can happen in a variety of fashions,
|
||||
// so we have to consult AtEnd().
|
||||
return (AtEnd() && typed_other->AtEnd()) ||
|
||||
($for j && [[
|
||||
|
||||
current$(j)_ == typed_other->current$(j)_
|
||||
]]);
|
||||
}
|
||||
|
||||
private:
|
||||
Iterator(const Iterator& other)
|
||||
: base_(other.base_), $for j, [[
|
||||
|
||||
begin$(j)_(other.begin$(j)_),
|
||||
end$(j)_(other.end$(j)_),
|
||||
current$(j)_(other.current$(j)_)
|
||||
]] {
|
||||
ComputeCurrentValue();
|
||||
}
|
||||
|
||||
void ComputeCurrentValue() {
|
||||
if (!AtEnd())
|
||||
current_value_ = ParamType($for j, [[*current$(j)_]]);
|
||||
}
|
||||
bool AtEnd() const {
|
||||
// We must report iterator past the end of the range when either of the
|
||||
// component iterators has reached the end of its range.
|
||||
return
|
||||
$for j || [[
|
||||
|
||||
current$(j)_ == end$(j)_
|
||||
]];
|
||||
}
|
||||
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const Iterator& other);
|
||||
|
||||
const ParamGeneratorInterface<ParamType>* const base_;
|
||||
// begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
|
||||
// current[i]_ is the actual traversing iterator.
|
||||
$for j [[
|
||||
|
||||
const typename ParamGenerator<T$j>::iterator begin$(j)_;
|
||||
const typename ParamGenerator<T$j>::iterator end$(j)_;
|
||||
typename ParamGenerator<T$j>::iterator current$(j)_;
|
||||
]]
|
||||
|
||||
ParamType current_value_;
|
||||
}; // class CartesianProductGenerator$i::Iterator
|
||||
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const CartesianProductGenerator$i& other);
|
||||
|
||||
|
||||
$for j [[
|
||||
const ParamGenerator<T$j> g$(j)_;
|
||||
|
||||
]]
|
||||
}; // class CartesianProductGenerator$i
|
||||
|
||||
|
||||
]]
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Helper classes providing Combine() with polymorphic features. They allow
|
||||
// casting CartesianProductGeneratorN<T> to ParamGenerator<U> if T is
|
||||
// convertible to U.
|
||||
//
|
||||
$range i 2..maxtuple
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
|
||||
template <$for j, [[class Generator$j]]>
|
||||
class CartesianProductHolder$i {
|
||||
public:
|
||||
CartesianProductHolder$i($for j, [[const Generator$j& g$j]])
|
||||
: $for j, [[g$(j)_(g$j)]] {}
|
||||
template <$for j, [[typename T$j]]>
|
||||
operator ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >() const {
|
||||
return ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >(
|
||||
new CartesianProductGenerator$i<$for j, [[T$j]]>(
|
||||
$for j,[[
|
||||
|
||||
static_cast<ParamGenerator<T$j> >(g$(j)_)
|
||||
]]));
|
||||
}
|
||||
|
||||
private:
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const CartesianProductHolder$i& other);
|
||||
|
||||
|
||||
$for j [[
|
||||
const Generator$j g$(j)_;
|
||||
|
||||
]]
|
||||
}; // class CartesianProductHolder$i
|
||||
|
||||
]]
|
||||
|
||||
# endif // GTEST_HAS_COMBINE
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_HAS_PARAM_TEST
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
|
619
thirdparty/gtest/include/gtest/internal/gtest-param-util.h
vendored
Normal file
619
thirdparty/gtest/include/gtest/internal/gtest-param-util.h
vendored
Normal file
@ -0,0 +1,619 @@
|
||||
// Copyright 2008 Google Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: vladl@google.com (Vlad Losev)
|
||||
|
||||
// Type and function utilities for implementing parameterized tests.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
|
||||
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
// scripts/fuse_gtest.py depends on gtest's own header being #included
|
||||
// *unconditionally*. Therefore these #includes cannot be moved
|
||||
// inside #if GTEST_HAS_PARAM_TEST.
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
#include "gtest/internal/gtest-linked_ptr.h"
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
#include "gtest/gtest-printers.h"
|
||||
|
||||
#if GTEST_HAS_PARAM_TEST
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Outputs a message explaining invalid registration of different
|
||||
// fixture class for the same test case. This may happen when
|
||||
// TEST_P macro is used to define two tests with the same name
|
||||
// but in different namespaces.
|
||||
GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name,
|
||||
const char* file, int line);
|
||||
|
||||
template <typename> class ParamGeneratorInterface;
|
||||
template <typename> class ParamGenerator;
|
||||
|
||||
// Interface for iterating over elements provided by an implementation
|
||||
// of ParamGeneratorInterface<T>.
|
||||
template <typename T>
|
||||
class ParamIteratorInterface {
|
||||
public:
|
||||
virtual ~ParamIteratorInterface() {}
|
||||
// A pointer to the base generator instance.
|
||||
// Used only for the purposes of iterator comparison
|
||||
// to make sure that two iterators belong to the same generator.
|
||||
virtual const ParamGeneratorInterface<T>* BaseGenerator() const = 0;
|
||||
// Advances iterator to point to the next element
|
||||
// provided by the generator. The caller is responsible
|
||||
// for not calling Advance() on an iterator equal to
|
||||
// BaseGenerator()->End().
|
||||
virtual void Advance() = 0;
|
||||
// Clones the iterator object. Used for implementing copy semantics
|
||||
// of ParamIterator<T>.
|
||||
virtual ParamIteratorInterface* Clone() const = 0;
|
||||
// Dereferences the current iterator and provides (read-only) access
|
||||
// to the pointed value. It is the caller's responsibility not to call
|
||||
// Current() on an iterator equal to BaseGenerator()->End().
|
||||
// Used for implementing ParamGenerator<T>::operator*().
|
||||
virtual const T* Current() const = 0;
|
||||
// Determines whether the given iterator and other point to the same
|
||||
// element in the sequence generated by the generator.
|
||||
// Used for implementing ParamGenerator<T>::operator==().
|
||||
virtual bool Equals(const ParamIteratorInterface& other) const = 0;
|
||||
};
|
||||
|
||||
// Class iterating over elements provided by an implementation of
|
||||
// ParamGeneratorInterface<T>. It wraps ParamIteratorInterface<T>
|
||||
// and implements the const forward iterator concept.
|
||||
template <typename T>
|
||||
class ParamIterator {
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef const T& reference;
|
||||
typedef ptrdiff_t difference_type;
|
||||
|
||||
// ParamIterator assumes ownership of the impl_ pointer.
|
||||
ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {}
|
||||
ParamIterator& operator=(const ParamIterator& other) {
|
||||
if (this != &other)
|
||||
impl_.reset(other.impl_->Clone());
|
||||
return *this;
|
||||
}
|
||||
|
||||
const T& operator*() const { return *impl_->Current(); }
|
||||
const T* operator->() const { return impl_->Current(); }
|
||||
// Prefix version of operator++.
|
||||
ParamIterator& operator++() {
|
||||
impl_->Advance();
|
||||
return *this;
|
||||
}
|
||||
// Postfix version of operator++.
|
||||
ParamIterator operator++(int /*unused*/) {
|
||||
ParamIteratorInterface<T>* clone = impl_->Clone();
|
||||
impl_->Advance();
|
||||
return ParamIterator(clone);
|
||||
}
|
||||
bool operator==(const ParamIterator& other) const {
|
||||
return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_);
|
||||
}
|
||||
bool operator!=(const ParamIterator& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ParamGenerator<T>;
|
||||
explicit ParamIterator(ParamIteratorInterface<T>* impl) : impl_(impl) {}
|
||||
scoped_ptr<ParamIteratorInterface<T> > impl_;
|
||||
};
|
||||
|
||||
// ParamGeneratorInterface<T> is the binary interface to access generators
|
||||
// defined in other translation units.
|
||||
template <typename T>
|
||||
class ParamGeneratorInterface {
|
||||
public:
|
||||
typedef T ParamType;
|
||||
|
||||
virtual ~ParamGeneratorInterface() {}
|
||||
|
||||
// Generator interface definition
|
||||
virtual ParamIteratorInterface<T>* Begin() const = 0;
|
||||
virtual ParamIteratorInterface<T>* End() const = 0;
|
||||
};
|
||||
|
||||
// Wraps ParamGeneratorInterface<T> and provides general generator syntax
|
||||
// compatible with the STL Container concept.
|
||||
// This class implements copy initialization semantics and the contained
|
||||
// ParamGeneratorInterface<T> instance is shared among all copies
|
||||
// of the original object. This is possible because that instance is immutable.
|
||||
template<typename T>
|
||||
class ParamGenerator {
|
||||
public:
|
||||
typedef ParamIterator<T> iterator;
|
||||
|
||||
explicit ParamGenerator(ParamGeneratorInterface<T>* impl) : impl_(impl) {}
|
||||
ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {}
|
||||
|
||||
ParamGenerator& operator=(const ParamGenerator& other) {
|
||||
impl_ = other.impl_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator begin() const { return iterator(impl_->Begin()); }
|
||||
iterator end() const { return iterator(impl_->End()); }
|
||||
|
||||
private:
|
||||
linked_ptr<const ParamGeneratorInterface<T> > impl_;
|
||||
};
|
||||
|
||||
// Generates values from a range of two comparable values. Can be used to
|
||||
// generate sequences of user-defined types that implement operator+() and
|
||||
// operator<().
|
||||
// This class is used in the Range() function.
|
||||
template <typename T, typename IncrementT>
|
||||
class RangeGenerator : public ParamGeneratorInterface<T> {
|
||||
public:
|
||||
RangeGenerator(T begin, T end, IncrementT step)
|
||||
: begin_(begin), end_(end),
|
||||
step_(step), end_index_(CalculateEndIndex(begin, end, step)) {}
|
||||
virtual ~RangeGenerator() {}
|
||||
|
||||
virtual ParamIteratorInterface<T>* Begin() const {
|
||||
return new Iterator(this, begin_, 0, step_);
|
||||
}
|
||||
virtual ParamIteratorInterface<T>* End() const {
|
||||
return new Iterator(this, end_, end_index_, step_);
|
||||
}
|
||||
|
||||
private:
|
||||
class Iterator : public ParamIteratorInterface<T> {
|
||||
public:
|
||||
Iterator(const ParamGeneratorInterface<T>* base, T value, int index,
|
||||
IncrementT step)
|
||||
: base_(base), value_(value), index_(index), step_(step) {}
|
||||
virtual ~Iterator() {}
|
||||
|
||||
virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
|
||||
return base_;
|
||||
}
|
||||
virtual void Advance() {
|
||||
value_ = value_ + step_;
|
||||
index_++;
|
||||
}
|
||||
virtual ParamIteratorInterface<T>* Clone() const {
|
||||
return new Iterator(*this);
|
||||
}
|
||||
virtual const T* Current() const { return &value_; }
|
||||
virtual bool Equals(const ParamIteratorInterface<T>& other) const {
|
||||
// Having the same base generator guarantees that the other
|
||||
// iterator is of the same type and we can downcast.
|
||||
GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
|
||||
<< "The program attempted to compare iterators "
|
||||
<< "from different generators." << std::endl;
|
||||
const int other_index =
|
||||
CheckedDowncastToActualType<const Iterator>(&other)->index_;
|
||||
return index_ == other_index;
|
||||
}
|
||||
|
||||
private:
|
||||
Iterator(const Iterator& other)
|
||||
: ParamIteratorInterface<T>(),
|
||||
base_(other.base_), value_(other.value_), index_(other.index_),
|
||||
step_(other.step_) {}
|
||||
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const Iterator& other);
|
||||
|
||||
const ParamGeneratorInterface<T>* const base_;
|
||||
T value_;
|
||||
int index_;
|
||||
const IncrementT step_;
|
||||
}; // class RangeGenerator::Iterator
|
||||
|
||||
static int CalculateEndIndex(const T& begin,
|
||||
const T& end,
|
||||
const IncrementT& step) {
|
||||
int end_index = 0;
|
||||
for (T i = begin; i < end; i = i + step)
|
||||
end_index++;
|
||||
return end_index;
|
||||
}
|
||||
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const RangeGenerator& other);
|
||||
|
||||
const T begin_;
|
||||
const T end_;
|
||||
const IncrementT step_;
|
||||
// The index for the end() iterator. All the elements in the generated
|
||||
// sequence are indexed (0-based) to aid iterator comparison.
|
||||
const int end_index_;
|
||||
}; // class RangeGenerator
|
||||
|
||||
|
||||
// Generates values from a pair of STL-style iterators. Used in the
|
||||
// ValuesIn() function. The elements are copied from the source range
|
||||
// since the source can be located on the stack, and the generator
|
||||
// is likely to persist beyond that stack frame.
|
||||
template <typename T>
|
||||
class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
|
||||
public:
|
||||
template <typename ForwardIterator>
|
||||
ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end)
|
||||
: container_(begin, end) {}
|
||||
virtual ~ValuesInIteratorRangeGenerator() {}
|
||||
|
||||
virtual ParamIteratorInterface<T>* Begin() const {
|
||||
return new Iterator(this, container_.begin());
|
||||
}
|
||||
virtual ParamIteratorInterface<T>* End() const {
|
||||
return new Iterator(this, container_.end());
|
||||
}
|
||||
|
||||
private:
|
||||
typedef typename ::std::vector<T> ContainerType;
|
||||
|
||||
class Iterator : public ParamIteratorInterface<T> {
|
||||
public:
|
||||
Iterator(const ParamGeneratorInterface<T>* base,
|
||||
typename ContainerType::const_iterator iterator)
|
||||
: base_(base), iterator_(iterator) {}
|
||||
virtual ~Iterator() {}
|
||||
|
||||
virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
|
||||
return base_;
|
||||
}
|
||||
virtual void Advance() {
|
||||
++iterator_;
|
||||
value_.reset();
|
||||
}
|
||||
virtual ParamIteratorInterface<T>* Clone() const {
|
||||
return new Iterator(*this);
|
||||
}
|
||||
// We need to use cached value referenced by iterator_ because *iterator_
|
||||
// can return a temporary object (and of type other then T), so just
|
||||
// having "return &*iterator_;" doesn't work.
|
||||
// value_ is updated here and not in Advance() because Advance()
|
||||
// can advance iterator_ beyond the end of the range, and we cannot
|
||||
// detect that fact. The client code, on the other hand, is
|
||||
// responsible for not calling Current() on an out-of-range iterator.
|
||||
virtual const T* Current() const {
|
||||
if (value_.get() == NULL)
|
||||
value_.reset(new T(*iterator_));
|
||||
return value_.get();
|
||||
}
|
||||
virtual bool Equals(const ParamIteratorInterface<T>& other) const {
|
||||
// Having the same base generator guarantees that the other
|
||||
// iterator is of the same type and we can downcast.
|
||||
GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
|
||||
<< "The program attempted to compare iterators "
|
||||
<< "from different generators." << std::endl;
|
||||
return iterator_ ==
|
||||
CheckedDowncastToActualType<const Iterator>(&other)->iterator_;
|
||||
}
|
||||
|
||||
private:
|
||||
Iterator(const Iterator& other)
|
||||
// The explicit constructor call suppresses a false warning
|
||||
// emitted by gcc when supplied with the -Wextra option.
|
||||
: ParamIteratorInterface<T>(),
|
||||
base_(other.base_),
|
||||
iterator_(other.iterator_) {}
|
||||
|
||||
const ParamGeneratorInterface<T>* const base_;
|
||||
typename ContainerType::const_iterator iterator_;
|
||||
// A cached value of *iterator_. We keep it here to allow access by
|
||||
// pointer in the wrapping iterator's operator->().
|
||||
// value_ needs to be mutable to be accessed in Current().
|
||||
// Use of scoped_ptr helps manage cached value's lifetime,
|
||||
// which is bound by the lifespan of the iterator itself.
|
||||
mutable scoped_ptr<const T> value_;
|
||||
}; // class ValuesInIteratorRangeGenerator::Iterator
|
||||
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const ValuesInIteratorRangeGenerator& other);
|
||||
|
||||
const ContainerType container_;
|
||||
}; // class ValuesInIteratorRangeGenerator
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Stores a parameter value and later creates tests parameterized with that
|
||||
// value.
|
||||
template <class TestClass>
|
||||
class ParameterizedTestFactory : public TestFactoryBase {
|
||||
public:
|
||||
typedef typename TestClass::ParamType ParamType;
|
||||
explicit ParameterizedTestFactory(ParamType parameter) :
|
||||
parameter_(parameter) {}
|
||||
virtual Test* CreateTest() {
|
||||
TestClass::SetParam(¶meter_);
|
||||
return new TestClass();
|
||||
}
|
||||
|
||||
private:
|
||||
const ParamType parameter_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory);
|
||||
};
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// TestMetaFactoryBase is a base class for meta-factories that create
|
||||
// test factories for passing into MakeAndRegisterTestInfo function.
|
||||
template <class ParamType>
|
||||
class TestMetaFactoryBase {
|
||||
public:
|
||||
virtual ~TestMetaFactoryBase() {}
|
||||
|
||||
virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0;
|
||||
};
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// TestMetaFactory creates test factories for passing into
|
||||
// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives
|
||||
// ownership of test factory pointer, same factory object cannot be passed
|
||||
// into that method twice. But ParameterizedTestCaseInfo is going to call
|
||||
// it for each Test/Parameter value combination. Thus it needs meta factory
|
||||
// creator class.
|
||||
template <class TestCase>
|
||||
class TestMetaFactory
|
||||
: public TestMetaFactoryBase<typename TestCase::ParamType> {
|
||||
public:
|
||||
typedef typename TestCase::ParamType ParamType;
|
||||
|
||||
TestMetaFactory() {}
|
||||
|
||||
virtual TestFactoryBase* CreateTestFactory(ParamType parameter) {
|
||||
return new ParameterizedTestFactory<TestCase>(parameter);
|
||||
}
|
||||
|
||||
private:
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory);
|
||||
};
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// ParameterizedTestCaseInfoBase is a generic interface
|
||||
// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase
|
||||
// accumulates test information provided by TEST_P macro invocations
|
||||
// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations
|
||||
// and uses that information to register all resulting test instances
|
||||
// in RegisterTests method. The ParameterizeTestCaseRegistry class holds
|
||||
// a collection of pointers to the ParameterizedTestCaseInfo objects
|
||||
// and calls RegisterTests() on each of them when asked.
|
||||
class ParameterizedTestCaseInfoBase {
|
||||
public:
|
||||
virtual ~ParameterizedTestCaseInfoBase() {}
|
||||
|
||||
// Base part of test case name for display purposes.
|
||||
virtual const string& GetTestCaseName() const = 0;
|
||||
// Test case id to verify identity.
|
||||
virtual TypeId GetTestCaseTypeId() const = 0;
|
||||
// UnitTest class invokes this method to register tests in this
|
||||
// test case right before running them in RUN_ALL_TESTS macro.
|
||||
// This method should not be called more then once on any single
|
||||
// instance of a ParameterizedTestCaseInfoBase derived class.
|
||||
virtual void RegisterTests() = 0;
|
||||
|
||||
protected:
|
||||
ParameterizedTestCaseInfoBase() {}
|
||||
|
||||
private:
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase);
|
||||
};
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P
|
||||
// macro invocations for a particular test case and generators
|
||||
// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that
|
||||
// test case. It registers tests with all values generated by all
|
||||
// generators when asked.
|
||||
template <class TestCase>
|
||||
class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
|
||||
public:
|
||||
// ParamType and GeneratorCreationFunc are private types but are required
|
||||
// for declarations of public methods AddTestPattern() and
|
||||
// AddTestCaseInstantiation().
|
||||
typedef typename TestCase::ParamType ParamType;
|
||||
// A function that returns an instance of appropriate generator type.
|
||||
typedef ParamGenerator<ParamType>(GeneratorCreationFunc)();
|
||||
|
||||
explicit ParameterizedTestCaseInfo(const char* name)
|
||||
: test_case_name_(name) {}
|
||||
|
||||
// Test case base name for display purposes.
|
||||
virtual const string& GetTestCaseName() const { return test_case_name_; }
|
||||
// Test case id to verify identity.
|
||||
virtual TypeId GetTestCaseTypeId() const { return GetTypeId<TestCase>(); }
|
||||
// TEST_P macro uses AddTestPattern() to record information
|
||||
// about a single test in a LocalTestInfo structure.
|
||||
// test_case_name is the base name of the test case (without invocation
|
||||
// prefix). test_base_name is the name of an individual test without
|
||||
// parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is
|
||||
// test case base name and DoBar is test base name.
|
||||
void AddTestPattern(const char* test_case_name,
|
||||
const char* test_base_name,
|
||||
TestMetaFactoryBase<ParamType>* meta_factory) {
|
||||
tests_.push_back(linked_ptr<TestInfo>(new TestInfo(test_case_name,
|
||||
test_base_name,
|
||||
meta_factory)));
|
||||
}
|
||||
// INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information
|
||||
// about a generator.
|
||||
int AddTestCaseInstantiation(const string& instantiation_name,
|
||||
GeneratorCreationFunc* func,
|
||||
const char* /* file */,
|
||||
int /* line */) {
|
||||
instantiations_.push_back(::std::make_pair(instantiation_name, func));
|
||||
return 0; // Return value used only to run this method in namespace scope.
|
||||
}
|
||||
// UnitTest class invokes this method to register tests in this test case
|
||||
// test cases right before running tests in RUN_ALL_TESTS macro.
|
||||
// This method should not be called more then once on any single
|
||||
// instance of a ParameterizedTestCaseInfoBase derived class.
|
||||
// UnitTest has a guard to prevent from calling this method more then once.
|
||||
virtual void RegisterTests() {
|
||||
for (typename TestInfoContainer::iterator test_it = tests_.begin();
|
||||
test_it != tests_.end(); ++test_it) {
|
||||
linked_ptr<TestInfo> test_info = *test_it;
|
||||
for (typename InstantiationContainer::iterator gen_it =
|
||||
instantiations_.begin(); gen_it != instantiations_.end();
|
||||
++gen_it) {
|
||||
const string& instantiation_name = gen_it->first;
|
||||
ParamGenerator<ParamType> generator((*gen_it->second)());
|
||||
|
||||
Message test_case_name_stream;
|
||||
if ( !instantiation_name.empty() )
|
||||
test_case_name_stream << instantiation_name << "/";
|
||||
test_case_name_stream << test_info->test_case_base_name;
|
||||
|
||||
int i = 0;
|
||||
for (typename ParamGenerator<ParamType>::iterator param_it =
|
||||
generator.begin();
|
||||
param_it != generator.end(); ++param_it, ++i) {
|
||||
Message test_name_stream;
|
||||
test_name_stream << test_info->test_base_name << "/" << i;
|
||||
MakeAndRegisterTestInfo(
|
||||
test_case_name_stream.GetString().c_str(),
|
||||
test_name_stream.GetString().c_str(),
|
||||
NULL, // No type parameter.
|
||||
PrintToString(*param_it).c_str(),
|
||||
GetTestCaseTypeId(),
|
||||
TestCase::SetUpTestCase,
|
||||
TestCase::TearDownTestCase,
|
||||
test_info->test_meta_factory->CreateTestFactory(*param_it));
|
||||
} // for param_it
|
||||
} // for gen_it
|
||||
} // for test_it
|
||||
} // RegisterTests
|
||||
|
||||
private:
|
||||
// LocalTestInfo structure keeps information about a single test registered
|
||||
// with TEST_P macro.
|
||||
struct TestInfo {
|
||||
TestInfo(const char* a_test_case_base_name,
|
||||
const char* a_test_base_name,
|
||||
TestMetaFactoryBase<ParamType>* a_test_meta_factory) :
|
||||
test_case_base_name(a_test_case_base_name),
|
||||
test_base_name(a_test_base_name),
|
||||
test_meta_factory(a_test_meta_factory) {}
|
||||
|
||||
const string test_case_base_name;
|
||||
const string test_base_name;
|
||||
const scoped_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory;
|
||||
};
|
||||
typedef ::std::vector<linked_ptr<TestInfo> > TestInfoContainer;
|
||||
// Keeps pairs of <Instantiation name, Sequence generator creation function>
|
||||
// received from INSTANTIATE_TEST_CASE_P macros.
|
||||
typedef ::std::vector<std::pair<string, GeneratorCreationFunc*> >
|
||||
InstantiationContainer;
|
||||
|
||||
const string test_case_name_;
|
||||
TestInfoContainer tests_;
|
||||
InstantiationContainer instantiations_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo);
|
||||
}; // class ParameterizedTestCaseInfo
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase
|
||||
// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P
|
||||
// macros use it to locate their corresponding ParameterizedTestCaseInfo
|
||||
// descriptors.
|
||||
class ParameterizedTestCaseRegistry {
|
||||
public:
|
||||
ParameterizedTestCaseRegistry() {}
|
||||
~ParameterizedTestCaseRegistry() {
|
||||
for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
|
||||
it != test_case_infos_.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
// Looks up or creates and returns a structure containing information about
|
||||
// tests and instantiations of a particular test case.
|
||||
template <class TestCase>
|
||||
ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder(
|
||||
const char* test_case_name,
|
||||
const char* file,
|
||||
int line) {
|
||||
ParameterizedTestCaseInfo<TestCase>* typed_test_info = NULL;
|
||||
for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
|
||||
it != test_case_infos_.end(); ++it) {
|
||||
if ((*it)->GetTestCaseName() == test_case_name) {
|
||||
if ((*it)->GetTestCaseTypeId() != GetTypeId<TestCase>()) {
|
||||
// Complain about incorrect usage of Google Test facilities
|
||||
// and terminate the program since we cannot guaranty correct
|
||||
// test case setup and tear-down in this case.
|
||||
ReportInvalidTestCaseType(test_case_name, file, line);
|
||||
posix::Abort();
|
||||
} else {
|
||||
// At this point we are sure that the object we found is of the same
|
||||
// type we are looking for, so we downcast it to that type
|
||||
// without further checks.
|
||||
typed_test_info = CheckedDowncastToActualType<
|
||||
ParameterizedTestCaseInfo<TestCase> >(*it);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (typed_test_info == NULL) {
|
||||
typed_test_info = new ParameterizedTestCaseInfo<TestCase>(test_case_name);
|
||||
test_case_infos_.push_back(typed_test_info);
|
||||
}
|
||||
return typed_test_info;
|
||||
}
|
||||
void RegisterTests() {
|
||||
for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
|
||||
it != test_case_infos_.end(); ++it) {
|
||||
(*it)->RegisterTests();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
typedef ::std::vector<ParameterizedTestCaseInfoBase*> TestCaseInfoContainer;
|
||||
|
||||
TestCaseInfoContainer test_case_infos_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_HAS_PARAM_TEST
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
|
1775
thirdparty/gtest/include/gtest/internal/gtest-port.h
vendored
Normal file
1775
thirdparty/gtest/include/gtest/internal/gtest-port.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
350
thirdparty/gtest/include/gtest/internal/gtest-string.h
vendored
Normal file
350
thirdparty/gtest/include/gtest/internal/gtest-string.h
vendored
Normal file
@ -0,0 +1,350 @@
|
||||
// Copyright 2005, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
|
||||
//
|
||||
// The Google C++ Testing Framework (Google Test)
|
||||
//
|
||||
// This header file declares the String class and functions used internally by
|
||||
// Google Test. They are subject to change without notice. They should not used
|
||||
// by code external to Google Test.
|
||||
//
|
||||
// This header file is #included by <gtest/internal/gtest-internal.h>.
|
||||
// It should not be #included by other files.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
// string.h is not guaranteed to provide strcpy on C++ Builder.
|
||||
# include <mem.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
// String - a UTF-8 string class.
|
||||
//
|
||||
// For historic reasons, we don't use std::string.
|
||||
//
|
||||
// TODO(wan@google.com): replace this class with std::string or
|
||||
// implement it in terms of the latter.
|
||||
//
|
||||
// Note that String can represent both NULL and the empty string,
|
||||
// while std::string cannot represent NULL.
|
||||
//
|
||||
// NULL and the empty string are considered different. NULL is less
|
||||
// than anything (including the empty string) except itself.
|
||||
//
|
||||
// This class only provides minimum functionality necessary for
|
||||
// implementing Google Test. We do not intend to implement a full-fledged
|
||||
// string class here.
|
||||
//
|
||||
// Since the purpose of this class is to provide a substitute for
|
||||
// std::string on platforms where it cannot be used, we define a copy
|
||||
// constructor and assignment operators such that we don't need
|
||||
// conditional compilation in a lot of places.
|
||||
//
|
||||
// In order to make the representation efficient, the d'tor of String
|
||||
// is not virtual. Therefore DO NOT INHERIT FROM String.
|
||||
class GTEST_API_ String {
|
||||
public:
|
||||
// Static utility methods
|
||||
|
||||
// Returns the input enclosed in double quotes if it's not NULL;
|
||||
// otherwise returns "(null)". For example, "\"Hello\"" is returned
|
||||
// for input "Hello".
|
||||
//
|
||||
// This is useful for printing a C string in the syntax of a literal.
|
||||
//
|
||||
// Known issue: escape sequences are not handled yet.
|
||||
static String ShowCStringQuoted(const char* c_str);
|
||||
|
||||
// Clones a 0-terminated C string, allocating memory using new. The
|
||||
// caller is responsible for deleting the return value using
|
||||
// delete[]. Returns the cloned string, or NULL if the input is
|
||||
// NULL.
|
||||
//
|
||||
// This is different from strdup() in string.h, which allocates
|
||||
// memory using malloc().
|
||||
static const char* CloneCString(const char* c_str);
|
||||
|
||||
#if GTEST_OS_WINDOWS_MOBILE
|
||||
// Windows CE does not have the 'ANSI' versions of Win32 APIs. To be
|
||||
// able to pass strings to Win32 APIs on CE we need to convert them
|
||||
// to 'Unicode', UTF-16.
|
||||
|
||||
// Creates a UTF-16 wide string from the given ANSI string, allocating
|
||||
// memory using new. The caller is responsible for deleting the return
|
||||
// value using delete[]. Returns the wide string, or NULL if the
|
||||
// input is NULL.
|
||||
//
|
||||
// The wide string is created using the ANSI codepage (CP_ACP) to
|
||||
// match the behaviour of the ANSI versions of Win32 calls and the
|
||||
// C runtime.
|
||||
static LPCWSTR AnsiToUtf16(const char* c_str);
|
||||
|
||||
// Creates an ANSI string from the given wide string, allocating
|
||||
// memory using new. The caller is responsible for deleting the return
|
||||
// value using delete[]. Returns the ANSI string, or NULL if the
|
||||
// input is NULL.
|
||||
//
|
||||
// The returned string is created using the ANSI codepage (CP_ACP) to
|
||||
// match the behaviour of the ANSI versions of Win32 calls and the
|
||||
// C runtime.
|
||||
static const char* Utf16ToAnsi(LPCWSTR utf16_str);
|
||||
#endif
|
||||
|
||||
// Compares two C strings. Returns true iff they have the same content.
|
||||
//
|
||||
// Unlike strcmp(), this function can handle NULL argument(s). A
|
||||
// NULL C string is considered different to any non-NULL C string,
|
||||
// including the empty string.
|
||||
static bool CStringEquals(const char* lhs, const char* rhs);
|
||||
|
||||
// Converts a wide C string to a String using the UTF-8 encoding.
|
||||
// NULL will be converted to "(null)". If an error occurred during
|
||||
// the conversion, "(failed to convert from wide string)" is
|
||||
// returned.
|
||||
static String ShowWideCString(const wchar_t* wide_c_str);
|
||||
|
||||
// Similar to ShowWideCString(), except that this function encloses
|
||||
// the converted string in double quotes.
|
||||
static String ShowWideCStringQuoted(const wchar_t* wide_c_str);
|
||||
|
||||
// Compares two wide C strings. Returns true iff they have the same
|
||||
// content.
|
||||
//
|
||||
// Unlike wcscmp(), this function can handle NULL argument(s). A
|
||||
// NULL C string is considered different to any non-NULL C string,
|
||||
// including the empty string.
|
||||
static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs);
|
||||
|
||||
// Compares two C strings, ignoring case. Returns true iff they
|
||||
// have the same content.
|
||||
//
|
||||
// Unlike strcasecmp(), this function can handle NULL argument(s).
|
||||
// A NULL C string is considered different to any non-NULL C string,
|
||||
// including the empty string.
|
||||
static bool CaseInsensitiveCStringEquals(const char* lhs,
|
||||
const char* rhs);
|
||||
|
||||
// Compares two wide C strings, ignoring case. Returns true iff they
|
||||
// have the same content.
|
||||
//
|
||||
// Unlike wcscasecmp(), this function can handle NULL argument(s).
|
||||
// A NULL C string is considered different to any non-NULL wide C string,
|
||||
// including the empty string.
|
||||
// NB: The implementations on different platforms slightly differ.
|
||||
// On windows, this method uses _wcsicmp which compares according to LC_CTYPE
|
||||
// environment variable. On GNU platform this method uses wcscasecmp
|
||||
// which compares according to LC_CTYPE category of the current locale.
|
||||
// On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
|
||||
// current locale.
|
||||
static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
|
||||
const wchar_t* rhs);
|
||||
|
||||
// Formats a list of arguments to a String, using the same format
|
||||
// spec string as for printf.
|
||||
//
|
||||
// We do not use the StringPrintf class as it is not universally
|
||||
// available.
|
||||
//
|
||||
// The result is limited to 4096 characters (including the tailing
|
||||
// 0). If 4096 characters are not enough to format the input,
|
||||
// "<buffer exceeded>" is returned.
|
||||
static String Format(const char* format, ...);
|
||||
|
||||
// C'tors
|
||||
|
||||
// The default c'tor constructs a NULL string.
|
||||
String() : c_str_(NULL), length_(0) {}
|
||||
|
||||
// Constructs a String by cloning a 0-terminated C string.
|
||||
String(const char* a_c_str) { // NOLINT
|
||||
if (a_c_str == NULL) {
|
||||
c_str_ = NULL;
|
||||
length_ = 0;
|
||||
} else {
|
||||
ConstructNonNull(a_c_str, strlen(a_c_str));
|
||||
}
|
||||
}
|
||||
|
||||
// Constructs a String by copying a given number of chars from a
|
||||
// buffer. E.g. String("hello", 3) creates the string "hel",
|
||||
// String("a\0bcd", 4) creates "a\0bc", String(NULL, 0) creates "",
|
||||
// and String(NULL, 1) results in access violation.
|
||||
String(const char* buffer, size_t a_length) {
|
||||
ConstructNonNull(buffer, a_length);
|
||||
}
|
||||
|
||||
// The copy c'tor creates a new copy of the string. The two
|
||||
// String objects do not share content.
|
||||
String(const String& str) : c_str_(NULL), length_(0) { *this = str; }
|
||||
|
||||
// D'tor. String is intended to be a final class, so the d'tor
|
||||
// doesn't need to be virtual.
|
||||
~String() { delete[] c_str_; }
|
||||
|
||||
// Allows a String to be implicitly converted to an ::std::string or
|
||||
// ::string, and vice versa. Converting a String containing a NULL
|
||||
// pointer to ::std::string or ::string is undefined behavior.
|
||||
// Converting a ::std::string or ::string containing an embedded NUL
|
||||
// character to a String will result in the prefix up to the first
|
||||
// NUL character.
|
||||
String(const ::std::string& str) {
|
||||
ConstructNonNull(str.c_str(), str.length());
|
||||
}
|
||||
|
||||
operator ::std::string() const { return ::std::string(c_str(), length()); }
|
||||
|
||||
#if GTEST_HAS_GLOBAL_STRING
|
||||
String(const ::string& str) {
|
||||
ConstructNonNull(str.c_str(), str.length());
|
||||
}
|
||||
|
||||
operator ::string() const { return ::string(c_str(), length()); }
|
||||
#endif // GTEST_HAS_GLOBAL_STRING
|
||||
|
||||
// Returns true iff this is an empty string (i.e. "").
|
||||
bool empty() const { return (c_str() != NULL) && (length() == 0); }
|
||||
|
||||
// Compares this with another String.
|
||||
// Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0
|
||||
// if this is greater than rhs.
|
||||
int Compare(const String& rhs) const;
|
||||
|
||||
// Returns true iff this String equals the given C string. A NULL
|
||||
// string and a non-NULL string are considered not equal.
|
||||
bool operator==(const char* a_c_str) const { return Compare(a_c_str) == 0; }
|
||||
|
||||
// Returns true iff this String is less than the given String. A
|
||||
// NULL string is considered less than "".
|
||||
bool operator<(const String& rhs) const { return Compare(rhs) < 0; }
|
||||
|
||||
// Returns true iff this String doesn't equal the given C string. A NULL
|
||||
// string and a non-NULL string are considered not equal.
|
||||
bool operator!=(const char* a_c_str) const { return !(*this == a_c_str); }
|
||||
|
||||
// Returns true iff this String ends with the given suffix. *Any*
|
||||
// String is considered to end with a NULL or empty suffix.
|
||||
bool EndsWith(const char* suffix) const;
|
||||
|
||||
// Returns true iff this String ends with the given suffix, not considering
|
||||
// case. Any String is considered to end with a NULL or empty suffix.
|
||||
bool EndsWithCaseInsensitive(const char* suffix) const;
|
||||
|
||||
// Returns the length of the encapsulated string, or 0 if the
|
||||
// string is NULL.
|
||||
size_t length() const { return length_; }
|
||||
|
||||
// Gets the 0-terminated C string this String object represents.
|
||||
// The String object still owns the string. Therefore the caller
|
||||
// should NOT delete the return value.
|
||||
const char* c_str() const { return c_str_; }
|
||||
|
||||
// Assigns a C string to this object. Self-assignment works.
|
||||
const String& operator=(const char* a_c_str) {
|
||||
return *this = String(a_c_str);
|
||||
}
|
||||
|
||||
// Assigns a String object to this object. Self-assignment works.
|
||||
const String& operator=(const String& rhs) {
|
||||
if (this != &rhs) {
|
||||
delete[] c_str_;
|
||||
if (rhs.c_str() == NULL) {
|
||||
c_str_ = NULL;
|
||||
length_ = 0;
|
||||
} else {
|
||||
ConstructNonNull(rhs.c_str(), rhs.length());
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
// Constructs a non-NULL String from the given content. This
|
||||
// function can only be called when c_str_ has not been allocated.
|
||||
// ConstructNonNull(NULL, 0) results in an empty string ("").
|
||||
// ConstructNonNull(NULL, non_zero) is undefined behavior.
|
||||
void ConstructNonNull(const char* buffer, size_t a_length) {
|
||||
char* const str = new char[a_length + 1];
|
||||
memcpy(str, buffer, a_length);
|
||||
str[a_length] = '\0';
|
||||
c_str_ = str;
|
||||
length_ = a_length;
|
||||
}
|
||||
|
||||
const char* c_str_;
|
||||
size_t length_;
|
||||
}; // class String
|
||||
|
||||
// Streams a String to an ostream. Each '\0' character in the String
|
||||
// is replaced with "\\0".
|
||||
inline ::std::ostream& operator<<(::std::ostream& os, const String& str) {
|
||||
if (str.c_str() == NULL) {
|
||||
os << "(null)";
|
||||
} else {
|
||||
const char* const c_str = str.c_str();
|
||||
for (size_t i = 0; i != str.length(); i++) {
|
||||
if (c_str[i] == '\0') {
|
||||
os << "\\0";
|
||||
} else {
|
||||
os << c_str[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
// Gets the content of the stringstream's buffer as a String. Each '\0'
|
||||
// character in the buffer is replaced with "\\0".
|
||||
GTEST_API_ String StringStreamToString(::std::stringstream* stream);
|
||||
|
||||
// Converts a streamable value to a String. A NULL pointer is
|
||||
// converted to "(null)". When the input value is a ::string,
|
||||
// ::std::string, ::wstring, or ::std::wstring object, each NUL
|
||||
// character in it is replaced with "\\0".
|
||||
|
||||
// Declared here but defined in gtest.h, so that it has access
|
||||
// to the definition of the Message class, required by the ARM
|
||||
// compiler.
|
||||
template <typename T>
|
||||
String StreamableToString(const T& streamable);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user