Move config set value fetches to new field framework

This commit is contained in:
Jason Perkins 2014-03-08 14:17:35 -05:00
parent 974b622b82
commit 9378d31295
8 changed files with 378 additions and 368 deletions

View File

@ -306,7 +306,7 @@
local target = api.gettarget(field.scope)
if not value then
return configset.fetchvalue(target.configset, field.name)
return configset.fetch(target.configset, field)
end
local status, result = pcall(function ()
@ -367,7 +367,7 @@
end
if value:contains("*") then
local current = configset.fetchvalue(target.configset, field.name)
local current = configset.fetch(target.configset, field)
local mask = path.wildcards(value)
for _, item in ipairs(current) do
if item:match(mask) == item then
@ -775,6 +775,99 @@
end
premake.field.kind("boolean", {
})
premake.field.kind("directory", {
})
premake.field.kind("file", {
})
premake.field.kind("integer", {
})
--
-- Key-value data kind definition. Merges key domains; values may be any kind.
--
local function setKeyed(field, current, value, processor)
current = current or {}
for k, v in pairs(value) do
if type(k) == "number" then
current = setKeyed(field, current, v, processor)
else
if processor then
v = processor(field, current[k], v)
end
current[k] = v
end
end
return current
end
premake.field.kind("keyed", {
merge = setKeyed
})
--
-- List data kind definition. Actually a misnomer, lists are more like sets in
-- that duplicate values are weeded out; each will only appear once. Can
-- contain any other kind of data.
--
local function setList(field, current, value, processor)
if type(value) == "table" then
for _, item in ipairs(value) do
current = setList(field, current, item, processor)
end
return current
end
current = current or {}
if current[value] then
table.remove(current, table.indexof(current, value))
end
table.insert(current, value)
current[value] = value
return current
end
premake.field.kind("list", {
merge = setList,
})
premake.field.kind("mixed", {
})
premake.field.kind("number", {
})
premake.field.kind("path", {
})
premake.field.kind("string", {
})
premake.field.kind("table", {
})
--
-- Start a new block of configuration settings.
--

View File

@ -1,19 +1,16 @@
--
-- configset.lua
--
-- DO NOT USE THIS YET! I am just getting started here; please wait until
-- I've had a chance to build it out more before using.
-- A configuration set manages a collection of fields, which are organized
-- into "blocks". Each block stores a set of field-value pairs, along with
-- a list of terms which indicate the context in which those field values
-- should be applied.
--
-- A configuration set manages a collection of configuration values, which
-- are organized into "blocks". Each block stores a set of field-value pairs,
-- along with a list of terms which indicate the context in which those
-- values should be applied.
--
-- Configurations use the API definition to know what fields are available,
-- Configurations use the field definitions to know what fields are available,
-- and the corresponding value types for those fields. Only fields that have
-- been registered via api.register() can be stored.
-- been registered via field.new() can be stored.
--
-- Copyright (c) 2012 Jason Perkins and the Premake project
-- Copyright (c) 2012-2014 Jason Perkins and the Premake project
--
premake.configset = {}
@ -43,6 +40,103 @@
end
---
-- Retrieve a value from the configuration set.
--
-- @param cset
-- The configuration set to query.
-- @param field
-- The definition of field to be queried.
-- @param context
-- A list of lowercase context terms to use during the fetch. Only those
-- blocks with terms fully contained by this list will be considered in
-- determining the returned value. Terms should be lower case to make
-- the context filtering case-insensitive.
-- @param filename
-- An optional filename; if provided, only blocks with pattern that
-- matches the name will be considered.
-- @return
-- The requested value.
---
function configset.fetch(cset, field, context, filename)
if not context then
context = cset._current._criteria.terms
end
if premake.field.merges(field) then
return configset._fetchMerged(cset, field, context, filename)
else
return configset._fetchDirect(cset, field, context, filename)
end
end
function configset._fetchDirect(cset, field, filter, filename)
local key = field.name
local n = #cset._blocks
for i = n, 1, -1 do
local block = cset._blocks[i]
local value = block[key]
if value and (cset.compiled or configset.testblock(block, filter, filename)) then
-- If value is an object, return a copy of it so that any
-- changes later made to it by the caller won't alter the
-- original value (that was a tough bug to find)
if type(value) == "table" then
value = table.deepcopy(value)
end
return value
end
end
if cset._parent then
return configset._fetchDirect(cset._parent, field, filter, filename)
end
end
function configset._fetchMerged(cset, field, filter, filename)
local result = {}
local function remove(patterns)
for _, pattern in ipairs(patterns) do
local i = 1
while i <= #result do
local value = result[i]:lower()
if value:match(pattern) == value then
result[result[i]] = nil
table.remove(result, i)
else
i = i + 1
end
end
end
end
if cset._parent then
result = configset._fetchMerged(cset._parent, field, filter, filename)
end
local key = field.name
for _, block in ipairs(cset._blocks) do
if cset.compiled or configset.testblock(block, filter, filename) then
if block._removes and block._removes[key] then
remove(block._removes[key])
end
local value = block[key]
if value then
result = premake.field.merge(field, result, value)
end
end
end
return result
end
---
-- Create and return a metatable which allows a configuration set to act as a
-- "backing store" for a regular Lua table. Table operations that access a
@ -64,7 +158,7 @@
__index = function(tbl, key)
local f = premake.field.get(key)
if f then
return configset.fetchvalue(cset, f.name, cset._current._criteria.terms)
return configset.fetch(cset, f, cset._current._criteria.terms)
else
return nil
end
@ -74,7 +168,6 @@
--
-- Register a field that requires special handling.
--
@ -94,6 +187,7 @@
end
--
-- Create a new block of configuration field-value pairs, with the provided
-- set of context terms to control their application.
@ -123,6 +217,7 @@
end
--
-- Add a new field-value pair to the current configuration data block. The
-- data type of the field is taken into account when adding the values:
@ -154,6 +249,7 @@
end
--
-- Remove values from a configuration set.
--
@ -183,6 +279,7 @@
end
--
-- Check to see if a configuration set is empty; that is, it does
-- not contain any configuration blocks.
@ -198,12 +295,13 @@
end
--
-- Check to see if an individual configuration block applies to the
-- given context and filename.
--
local function testblock(block, context, filename)
function configset.testblock(block, context, filename)
-- Make file tests relative to the blocks base directory,
-- so path relative pattern matches will work.
if block._basedir and filename then
@ -213,6 +311,7 @@
end
--
-- Compiles a new configuration set containing only the blocks which match
-- the specified criteria. Fetches against this compiled configuration set
@ -245,7 +344,7 @@
-- add in my own blocks
for _, block in ipairs(cset._blocks) do
if testblock(block, context, filename) then
if configset.testblock(block, context, filename) then
table.insert(result._blocks, block)
end
end
@ -255,181 +354,4 @@
end
--
-- Merges two lists of values together. The merged list is both indexed
-- and keyed for faster lookups. If duplicate values are encountered,
-- the earlier value is removed.
--
local function merge(a, b)
-- if b is itself a list, flatten it out
if type(b) == "table" then
for _, v in ipairs(b) do
merge(a, v)
end
-- if b is a simple value, insert it
else
-- find and remove earlier values
if a[b] then
table.remove(a, table.indexof(a, b))
end
table.insert(a, b)
a[b] = b
end
end
--
-- Retrieve a directly assigned value from the configuration set. No merging
-- takes place; the last value set is the one returned.
--
local function fetchassign(cset, fieldname, context, filename)
-- walk the loop backwards and return on first value encountered
local n = #cset._blocks
for i = n, 1, -1 do
local block = cset._blocks[i]
if block[fieldname] and (cset.compiled or testblock(block, context, filename)) then
return block[fieldname]
end
end
if cset._parent then
return fetchassign(cset._parent, fieldname, context, filename)
end
end
--
-- Retrieve a keyed from the configuration set; keys are assembled into
-- a single result; values may optionally be merged too.
--
local function fetchkeyed(cset, fieldname, context, filename, mergevalues)
local result = {}
-- grab values from the parent set first
if cset._parent then
result = fetchkeyed(cset._parent, fieldname, context, filename, merge)
end
function process(values)
for k, v in pairs(values) do
if type(k) == "number" then
process(v)
elseif mergevalues then
result[k] = result[k] or {}
merge(result[k], v)
else
result[k] = v
end
end
end
for _, block in ipairs(cset._blocks) do
if cset.compiled or testblock(block, context, filename) then
local value = block[fieldname]
if value then
process(value)
end
end
end
return result
end
--
-- Retrieve a merged value from the configuration set; all values are
-- assembled together into a single result.
--
local function fetchmerge(cset, fieldname, context, filename)
local result = {}
-- grab values from the parent set first
if cset._parent then
result = fetchmerge(cset._parent, fieldname, context, filename)
end
function remove(patterns)
for _, pattern in ipairs(patterns) do
local i = 1
while i <= #result do
local value = result[i]:lower()
if value:match(pattern) == value then
result[result[i]] = nil
table.remove(result, i)
else
i = i + 1
end
end
end
end
for _, block in ipairs(cset._blocks) do
if cset.compiled or testblock(block, context, filename) then
if block._removes and block._removes[fieldname] then
remove(block._removes[fieldname])
end
local value = block[fieldname]
if value then
merge(result, value)
end
end
end
return result
end
--
-- Retrieve a value from the configuration set.
--
-- @param cset
-- The configuration set to query.
-- @param fieldname
-- The name of the field to query. The field should have already been
-- defined using the api.register() function.
-- @param context
-- A list of lowercase context terms to use during the fetch. Only those
-- blocks with terms fully contained by this list will be considered in
-- determining the returned value. Terms should be lower case to make
-- the context filtering case-insensitive.
-- @param filename
-- An optional filename; if provided, only blocks with pattern that
-- matches the name will be considered.
-- @return
-- The requested value.
--
function configset.fetchvalue(cset, fieldname, context, filename)
local value
if not context then
context = cset._current._criteria.terms
end
-- should this field be merged or assigned?
local field = configset._fields[fieldname]
local keyed = field and field.keyed
local merge = field and field.merge
if keyed then
value = fetchkeyed(cset, fieldname, context, filename, merge)
elseif merge then
value = fetchmerge(cset, fieldname, context, filename)
else
value = fetchassign(cset, fieldname, context, filename)
-- if value is an object, return a copy of it, so that they can
-- modified by the caller without altering the source data
if type(value) == "table" then
value = table.deepcopy(value)
end
end
return value
end

View File

@ -164,9 +164,9 @@
-- If there is a matching field, then go fetch the aggregated value
-- from my configuration set, and then cache it future lookups.
local value = configset.fetchvalue(ctx._cfgset, key, ctx.terms, ctx._filename[1])
local value = configset.fetch(ctx._cfgset, field, ctx.terms, ctx._filename[1])
if value then
-- do I need to expand tokens? -- local field = premake.fields[key]
-- do I need to expand tokens?
if field and field.tokens then
local kind = field.kind
local ispath = kind:startswith("path") or kind:startswith("file") or kind:startswith("mixed")

View File

@ -24,6 +24,9 @@
-- For historical reasons
premake.fields = field._list
-- A cache for data kind accessor functions
field._accessors = {}
---
@ -46,12 +49,133 @@
---
function field.new(f)
-- Translate the old approaches to data kind definitions to the new
-- one used here. These should probably be deprecated eventually.
local kind = f.kind
if f.list then
kind = "list:" .. kind
end
if f.keyed then
kind = "keyed:" .. kind
end
f._kind = kind
field._list[f.name] = f
return f
end
---
-- Register a new kind of data for field storage.
--
-- @param tag
-- A unique name of the kind; used in the kind string in new field
-- definitions (see new(), above).
-- @param functions
-- A table of processor functions for the new kind.
---
function field.kind(tag, functions)
field._kinds[tag] = functions
end
---
-- Build an "accessor" function to process incoming values for a field. This
-- function should be an interview question.
--
-- An accessor function takes the form of:
--
-- function (field, current, value, nextAccessor)
--
-- It receives the target field, the current value of that field, and the new
-- value that has been provided by the project script. It then returns the
-- new value for the target field.
--
-- @param f
-- The field for which an accessor should be returned.
-- @param method
-- The type of accessor function required; currently this should be one of
-- "set", "remove", or "merge" though it is possible for add-on modules to
-- extend the available methods by implementing appropriate processing
-- functions.
-- @return
-- An accessor function for the field's kind and method. May return nil
-- if no processing functions are available for the given method.
---
function field.accessor(f, method)
-- Prepare a cache for accessors using this method; each encountered
-- kind only needs to be fully processed once.
field._accessors[method] = field._accessors[method] or {}
local cache = field._accessors[method]
-- Helper function recurses over each piece of the field's data kind,
-- building an accessor function for each sequence encountered. Results
-- cached from earlier calls are reused again.
local function accessorForKind(kind)
-- Have I already cached a result from an earlier call?
if cache[kind] then
return cache[kind]
end
-- Split off the first piece from the rest of the kind. If the
-- incoming kind is "list:key:string", thisKind will "list" and
-- nextKind will be "key:string".
local thisKind = kind:match('(.-):') or kind
local nextKind = kind:sub(#thisKind + 2)
-- Get the processor function for this kind. Processors perform
-- data validation and storage appropriate for the data structure.
local functions = field._kinds[thisKind]
if not functions then
error("Invalid field kind '" .. thisKind .. "'")
end
local processor = functions[method]
if not processor then
return nil
end
-- Now recurse to get the accessor function for the remaining parts
-- of the field's data kind. If the kind was "list:key:string", then
-- the processor function handles the "list" part, and this function
-- takes care of the "key:string" part.
local nextAccessor = accessorForKind(nextKind)
-- Now here's the magic: wrap the processor and the next accessor
-- up together into a Matryoshka doll of function calls, each call
-- handling just it's level of the kind.
accessor = function(f, current, value)
return processor(f, current, value, nextAccessor)
end
-- And cache the result so I don't have to go through that again
cache[kind] = accessor
return accessor
end
-- The _kind is temporary; I'm using it while I transition off the old
-- codebase. Once everything is migrated it can go away.
return accessorForKind(f._kind or f.kind)
end
---
-- Fetch a field description by name.
---
@ -59,3 +183,25 @@
function field.get(name)
return field._list[name]
end
function field.merge(f, current, value)
local processor = field.accessor(f, "merge")
if processor then
return processor(f, current, value)
else
return value
end
end
---
-- Is this a field that supports merging values together? Non-merging fields
-- can simply overwrite their values, merging fields can call merge() to
-- combine two values together.
---
function field.merges(f)
return (field.accessor(f, "merge") ~= nil)
end

View File

@ -362,7 +362,7 @@
-- assemble all matching configmaps, and then merge their keys
-- into the project's configmap
local map = configset.fetchvalue(cset, "configmap", terms)
local map = configset.fetch(cset, premake.field.get("configmap"), terms)
if map then
for key, value in pairs(map) do
ctx.configmap[key] = value

View File

@ -1,151 +0,0 @@
--
-- tests/api/test_callback.lua
-- Tests the main API value-setting callback.
-- Copyright (c) 2012 Jason Perkins and the Premake project
--
T.api_callback = {}
local suite = T.api_callback
local api = premake.api
--
-- Setup and teardown
--
function suite.setup()
api.settest = function(target, name, field, value)
test_args = {
["target"] = target,
["name"] = name,
["field"] = field,
["value"] = value
}
end
end
function suite.teardown()
testapi = nil
test_args = nil
api.settest = nil
end
--
-- Verify that the callback hands off control to setter for
-- the field's value kind.
--
function suite.callsSetter_onFieldKind()
api.register { name = "testapi", kind = "test", scope = "project" }
solution "MySolution"
testapi "test"
test.isnotnil(test_args)
end
--
-- Verify that the target field name is getting passed to the setter.
--
function suite.setterGetsFieldName()
api.register { name = "testapi", kind = "test", scope = "project" }
solution "MySolution"
testapi "test"
test.isequal("testapi", test_args.name)
end
--
-- Verify that the field description is passed along to the setter.
--
function suite.setterGetsFieldDescription()
api.register { name = "testapi", kind = "test", scope = "project" }
solution "MySolution"
testapi "test"
test.isequal("testapi", test_args.field.name)
end
--
-- Verify that the value is passed along to the setter.
--
function suite.setterGetsFieldDescription()
api.register { name = "testapi", kind = "test", scope = "project" }
solution "MySolution"
testapi "test"
test.isequal("test", test_args.value)
end
--
-- If the field scope is "project" and there is an active solution, but not an
-- active project, the solution should be the target.
--
function suite.solutionTarget_onProjectScopeWithActiveSolution()
api.register { name = "testapi", kind = "test", scope = "project" }
local sln = solution "MySolution"
testapi "test"
test.istrue(sln == test_args.target)
end
--
-- If the field scope is "project" and there is an active project, it should
-- be the target.
--
function suite.projectTarget_onProjectScopeWithActiveProject()
api.register { name = "testapi", kind = "test", scope = "project" }
local sln = solution "MySolution"
local prj = project "MyProject"
testapi "test"
test.istrue(prj == test_args.target)
end
--
-- If the field scope is "configuration" and there is an active configuration,
-- it should be the target.
--
function suite.configTarget_onConfigScopeWithActiveConfig()
api.register { name = "testapi", kind = "test", scope = "configuration" }
local sln = solution "MySolution"
local cfg = configuration {}
testapi "test"
test.istrue(cfg == test_args.target)
end
--
-- On key-value APIs, the field name should be the key value from the supplied table.
--
function suite.keyObjectName_onKeyValue()
api.register { name = "testapi", kind = "test", keyed = true, scope = "project" }
local sln = solution "MySolution"
testapi { key = "test" }
test.isequal("key", test_args.name)
end
--
-- Raise an error is a simple value is passed to a key-value API.
--
function suite.keyValueRaisesError_onSimpleValue()
api.register { name = "testapi", kind = "test", keyed = true, scope = "project" }
local sln = solution "MySolution"
ok, err = pcall(function ()
testapi "test"
end)
test.isfalse(ok)
end

View File

@ -8,6 +8,7 @@
local suite = T.configset
local configset = premake.configset
local field = premake.field
--
@ -36,7 +37,7 @@
--
function suite.defaultValue_onString()
test.isnil(configset.fetchvalue(cset, "targetextension", {}))
test.isnil(configset.fetch(cset, field.get("targetextension"), {}))
end
@ -47,7 +48,7 @@
function suite.canRoundtrip_onDefaultBlock()
configset.addvalue(cset, "targetextension", ".so")
test.isequal(".so", configset.fetchvalue(cset, "targetextension", {}))
test.isequal(".so", configset.fetch(cset, field.get("targetextension"), {}))
end
@ -59,7 +60,7 @@
function suite.canRoundtrip_onSimpleTermMatch()
configset.addblock(cset, { "Windows" })
configset.addvalue(cset, "targetextension", ".dll")
test.isequal(".dll", configset.fetchvalue(cset, "targetextension", { "windows" }))
test.isequal(".dll", configset.fetch(cset, field.get("targetextension"), { "windows" }))
end
@ -72,7 +73,7 @@
configset.addvalue(cset, "targetextension", ".so")
configset.addblock(cset, { "Windows" })
configset.addvalue(cset, "targetextension", ".dll")
test.isequal(".so", configset.fetchvalue(cset, "targetextension", { "linux" }))
test.isequal(".so", configset.fetch(cset, field.get("targetextension"), { "linux" }))
end
@ -82,7 +83,7 @@
function suite.canRoundtrip_fromParentToChild()
configset.addvalue(parentset, "targetextension", ".so")
test.isequal(".so", configset.fetchvalue(cset, "targetextension", {}))
test.isequal(".so", configset.fetch(cset, field.get("targetextension"), {}))
end
@ -93,7 +94,7 @@
function suite.child_canOverrideStringValueFromParent()
configset.addvalue(parentset, "targetextension", ".so")
configset.addvalue(cset, "targetextension", ".dll")
test.isequal(".dll", configset.fetchvalue(cset, "targetextension", {}))
test.isequal(".dll", configset.fetch(cset, field.get("targetextension"), {}))
end
@ -105,7 +106,7 @@
function suite.filenameMadeRelative_onBaseDirSet()
configset.addblock(cset, { "hello.c" }, os.getcwd())
configset.addvalue(cset, "buildaction", "copy")
test.isequal("copy", configset.fetchvalue(cset, "buildaction", {}, path.join(os.getcwd(), "hello.c")))
test.isequal("copy", configset.fetch(cset, field.get("buildaction"), {}, path.join(os.getcwd(), "hello.c")))
end
@ -114,7 +115,7 @@
--
function suite.lists_returnsEmptyTable_onNotSet()
test.isequal({}, configset.fetchvalue(cset, "buildoptions", {}))
test.isequal({}, configset.fetch(cset, field.get("buildoptions"), {}))
end
@ -126,7 +127,7 @@
configset.addvalue(cset, "buildoptions", "v1")
configset.addblock(cset, { "windows" })
configset.addvalue(cset, "buildoptions", "v2")
test.isequal({"v1", "v2"}, configset.fetchvalue(cset, "buildoptions", {"windows"}))
test.isequal({"v1", "v2"}, configset.fetch(cset, field.get("buildoptions"), {"windows"}))
end
@ -137,7 +138,7 @@
function suite.lists_mergeValues_onAdd()
configset.addvalue(cset, "buildoptions", "v1")
configset.addvalue(cset, "buildoptions", "v2")
test.isequal({"v1", "v2"}, configset.fetchvalue(cset, "buildoptions", {"windows"}))
test.isequal({"v1", "v2"}, configset.fetch(cset, field.get("buildoptions"), {"windows"}))
end
@ -147,7 +148,7 @@
function suite.lists_includeValueKeys()
configset.addvalue(cset, "buildoptions", { "v1", "v2" })
local x = configset.fetchvalue(cset, "buildoptions", {})
local x = configset.fetch(cset, field.get("buildoptions"), {})
test.isequal("v2", x.v2)
end
@ -159,13 +160,13 @@
function suite.remove_onExactValueMatch()
configset.addvalue(cset, "flags", { "Symbols", "Unsafe", "NoRTTI" })
configset.removevalues(cset, "flags", { "Unsafe" })
test.isequal({ "Symbols", "NoRTTI" }, configset.fetchvalue(cset, "flags", {}))
test.isequal({ "Symbols", "NoRTTI" }, configset.fetch(cset, field.get("flags"), {}))
end
function suite.remove_onMultipleValues()
configset.addvalue(cset, "flags", { "Symbols", "NoExceptions", "Unsafe", "NoRTTI" })
configset.removevalues(cset, "flags", { "NoExceptions", "NoRTTI" })
test.isequal({ "Symbols", "Unsafe" }, configset.fetchvalue(cset, "flags", {}))
test.isequal({ "Symbols", "Unsafe" }, configset.fetch(cset, field.get("flags"), {}))
end
@ -176,7 +177,7 @@
function suite.remove_onWildcard()
configset.addvalue(cset, "defines", { "WIN32", "WIN64", "LINUX", "MACOSX" })
configset.removevalues(cset, "defines", { "WIN*" })
test.isequal({ "LINUX", "MACOSX" }, configset.fetchvalue(cset, "defines", {}))
test.isequal({ "LINUX", "MACOSX" }, configset.fetch(cset, field.get("defines"), {}))
end
@ -188,7 +189,7 @@
configset.addvalue(cset, "configmap", { Debug="Debug", Release="Release" })
configset.addblock(cset, { "windows" })
configset.addvalue(cset, "configmap", { Profile="Profile" })
local x = configset.fetchvalue(cset, "configmap", {"windows"})
local x = configset.fetch(cset, field.get("configmap"), {"windows"})
test.istrue(x.Debug and x.Release and x.Profile)
end
@ -200,7 +201,7 @@
function suite.keyed_mergesKeys_onAdd()
configset.addvalue(cset, "configmap", { Debug="Debug", Release="Release" })
configset.addvalue(cset, "configmap", { Profile="Profile" })
local x = configset.fetchvalue(cset, "configmap", {"windows"})
local x = configset.fetch(cset, field.get("configmap"), {"windows"})
test.istrue(x.Debug and x.Release and x.Profile)
end
@ -213,14 +214,14 @@
configset.addvalue(cset, "configmap", { Debug="Debug" })
configset.addblock(cset, { "windows" })
configset.addvalue(cset, "configmap", { Debug="Development" })
local x = configset.fetchvalue(cset, "configmap", {"windows"})
local x = configset.fetch(cset, field.get("configmap"), {"windows"})
test.isequal("Development", x.Debug)
end
function suite.keyed_overwritesValues_onNonMergeAdd()
configset.addvalue(cset, "configmap", { Debug="Debug" })
configset.addvalue(cset, "configmap", { Debug="Development" })
local x = configset.fetchvalue(cset, "configmap", {"windows"})
local x = configset.fetch(cset, field.get("configmap"), {"windows"})
test.isequal("Development", x.Debug)
end
@ -233,13 +234,13 @@
configset.addvalue(cset, "vpaths", { includes="*.h" })
configset.addblock(cset, { "windows" })
configset.addvalue(cset, "vpaths", { includes="*.hpp" })
local x = configset.fetchvalue(cset, "vpaths", {"windows"})
local x = configset.fetch(cset, field.get("vpaths"), {"windows"})
test.isequal({ "*.h", "*.hpp" }, x.includes)
end
function suite.keyed_mergesValues_onMergeAdd()
configset.addvalue(cset, "vpaths", { includes="*.h" })
configset.addvalue(cset, "vpaths", { includes="*.hpp" })
local x = configset.fetchvalue(cset, "vpaths", {"windows"})
local x = configset.fetch(cset, field.get("vpaths"), {"windows"})
test.isequal({ "*.h", "*.hpp" }, x.includes)
end

View File

@ -84,7 +84,6 @@
dofile("oven/test_filtering.lua")
-- API tests
dofile("api/test_callback.lua")
dofile("api/test_containers.lua")
dofile("api/test_directory_kind.lua")
dofile("api/test_list_kind.lua")