diff --git a/.gitignore b/.gitignore index fbea0f6..15d08ae 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ tests/test_nested_cmd tests/test_help tests/test_argument tests/test_parsecmdarg +tests/test_case_opt diff --git a/confutils.nim b/confutils.nim index dc84ea2..70e25b1 100644 --- a/confutils.nim +++ b/confutils.nim @@ -195,7 +195,7 @@ func helpOptDesc(appInfo: HelpAppInfo): string = func isCliSwitch(opt: OptInfo): bool = opt.kind == CliSwitch or - (opt.kind == Discriminator and opt.isCommand == false) + (opt.kind == Discriminator and not opt.isCommand) func isOpt(opt: OptInfo, excl: set[OptFlag]): bool = opt.isCliSwitch and excl * opt.flags == {} @@ -1280,6 +1280,8 @@ proc loadImpl[C, SecondarySources]( processHelpAndVersionOptions(key, val) var opt = findOpt(activeCmds, key) + #for x in activeCmds: + # debugEcho repr x if opt == nil: # We didn't find the option. # Check if it's from the default command and activate it if necessary: @@ -1294,7 +1296,14 @@ proc loadImpl[C, SecondarySources]( discard if opt != nil: - result.applySetter(opt.idx, val) + if opt.kind == Discriminator and not opt.isCommand: + let subCmd = findCmd(opt.subCmds, val) + if subCmd == nil: + fail "Unrecognized value '" & val & "'" & " for option '" & key & "'" + result.applySetter(opt.idx, if subCmd.desc.len > 0: subCmd.desc else: subCmd.name) + activeCmds.add subCmd + else: + result.applySetter(opt.idx, val) elif not ignoreUnknown: fail "Unrecognized option '" & key & "'" diff --git a/tests/test_all.nim b/tests/test_all.nim index 23f13ea..48df0e9 100644 --- a/tests/test_all.nim +++ b/tests/test_all.nim @@ -9,6 +9,7 @@ import test_argument, + test_case_opt, test_config_file, test_dispatch, test_duplicates, diff --git a/tests/test_case_opt.nim b/tests/test_case_opt.nim new file mode 100644 index 0000000..5f45c29 --- /dev/null +++ b/tests/test_case_opt.nim @@ -0,0 +1,162 @@ +# confutils +# Copyright (c) 2018-2026 Status Research & Development GmbH +# Licensed under either of +# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) +# * MIT license ([LICENSE-MIT](LICENSE-MIT)) +# at your option. +# This file may not be copied, modified, or distributed except according to +# those terms. + +import unittest2, ../confutils + +#type +# StartupCommand* = enum +# noCommand +# cmdSlotProcessing +# cmdBlockProcessing +# +# BlockProcessingCat* = enum +# catBlockHeader +# catAttestations +# catDeposits +# +# ScenarioConf* = object +# preState* {. +# desc: "The name of your pre-state (without .ssz)" +# name: "pre" +# abbr: "p" +# defaultValue: "pre".}: string +# case cmd*{. +# command +# defaultValue: noCommand }: StartupCommand +# of noCommand: +# discard +# of cmdSlotProcessing: +# numSlots* {. +# desc: "The number of slots the pre-state will be advanced by" +# name: "num-slots" +# abbr: "s" +# defaultValue: 1.}: uint64 +# of cmdBlockProcessing: +# case blockProcessingCat* {. +# desc: "block transitions" +# #name: "process-blocks" # Comment this to make it work +# implicitlySelectable +# required .}: BlockProcessingCat +# of catBlockHeader: +# discard +# of catAttestations: +# attestation*{. +# desc: "Attestation filename (without .ssz)" +# name: "attestation" +# defaultValue: "attestation default".}: string +# of catDeposits: +# discard +# +#suite "test case option": +# test "no command": +# let conf = ScenarioConf.load(cmdLine = @[]) +# check: +# conf.cmd == StartupCommand.noCommand +# conf.preState == "pre" +# +# test "case option has default value": +# let conf = ScenarioConf.load(cmdLine = @[ +# "cmdBlockProcessing", +# "--blockProcessingCat=catAttestations", +# "--attestation=attestation" +# ]) +# check: +# conf.cmd == StartupCommand.cmdBlockProcessing +# conf.blockProcessingCat == BlockProcessingCat.catAttestations +# conf.attestation == "attestation" + +type + StartupCommand* = enum + noCommand + cmdSlotProcessing + cmdBlockProcessing + + BlockProcessingCat* = enum + catBlockHeader + catAttestations + catDeposits + + TestConf = object + preState {. + desc: "The name of your pre-state (without .ssz)" + name: "pre" + abbr: "p" + defaultValue: "pre".}: string + case blockProcessingCat {. + desc: "block transitions" + #name: "process-blocks" # Comment this to make it work + implicitlySelectable + required .}: BlockProcessingCat + of catBlockHeader: + discard + of catAttestations: + attestation{. + desc: "Attestation filename (without .ssz)" + name: "attestation" + defaultValue: "attestation default".}: string + of catDeposits: + discard + + case block2 {. + desc: "block transitions" + #name: "process-blocks" # Comment this to make it work + implicitlySelectable + required .}: StartupCommand + of noCommand: + discard + of cmdSlotProcessing: + attestation2 {. + desc: "Attestation filename (without .ssz)" + name: "attestation2" + defaultValue: "attestation default".}: string + of cmdBlockProcessing: + discard + +suite "test case option": +# test "case option has default value": +# let conf = TestConf.load(cmdLine = @[ +# "--blockProcessingCat=catAttestations", +# #"--attestation=attestation" +# ]) +# check: +# conf.blockProcessingCat == BlockProcessingCat.catAttestations +# conf.attestation == "attestation default" +# +# test "case option set value": +# let conf = TestConf.load(cmdLine = @[ +# "--blockProcessingCat=catAttestations", +# "--attestation=foobar" +# ]) +# check: +# conf.blockProcessingCat == BlockProcessingCat.catAttestations +# conf.attestation == "foobar" +# +# test "case option set value": +# let conf = TestConf.load(cmdLine = @[ +# "--blockProcessingCat=catAttestations", +# "--attestation=foobar", +# "--pre=foo" +# ]) +# check: +# conf.blockProcessingCat == BlockProcessingCat.catAttestations +# conf.attestation == "foobar" +# conf.preState == "foo" + + test "case option set value": + let conf = TestConf.load(cmdLine = @[ + "--blockProcessingCat=catAttestations", + "--attestation=foobar", + "--block2=cmdSlotProcessing", + "--attestation2=bar" + ]) + check: + conf.blockProcessingCat == BlockProcessingCat.catAttestations + conf.block2 == StartupCommand.cmdSlotProcessing + conf.attestation == "foobar" + conf.attestation2 == "bar"