Default boolean arg to false

- In a case where arg is given as boolean and with plain
  @ShellOption (user doesn't define defaults), configure
  arg not to be mandatory and with default value false.
- This brings this spesific case more close how it behave
  in older shell version.
- Having `@ShellOption boolean arg1` it now works as:
    my-shell:>e2e reg default-value-boolean3
    Hello false
    my-shell:>e2e reg default-value-boolean3 --arg1
    Hello true
    my-shell:>e2e reg default-value-boolean3 --arg1 false
    Hello false
    my-shell:>e2e reg default-value-boolean3 --arg1 true
    Hello true
- Fixes #461
This commit is contained in:
Janne Valkealahti
2022-07-18 10:29:31 +01:00
parent 5ba8e185bc
commit 643b189fb8
4 changed files with 504 additions and 1 deletions

View File

@@ -74,6 +74,146 @@ describe('e2e commands default-value', () => {
await expect(cli.exitCode()).resolves.toBe(0);
};
/**
* testDefaultValueBoolean1 - 1
*/
const annoDefaultValueBoolean1WithoutArgReturnsFalseDesc = 'default boolean1 without arg returns false (anno)';
const annoDefaultValueBoolean1WithoutArgCommand = ['e2e anno default-value-boolean1'];
const annoDefaultValueBoolean1WithoutArgReturnsFalse = async (cli: Cli) => {
cli.run();
await waitForExpect(async () => {
const screen = cli.screen();
expect(screen).toEqual(expect.arrayContaining([expect.stringContaining('Hello false')]));
});
await expect(cli.exitCode()).resolves.toBe(0);
};
/**
* testDefaultValueBoolean1Registration - 1
*/
const regDefaultValueBoolean1WithoutArgReturnsFalseDesc = 'default boolean1 without arg returns false (reg)';
const regDefaultValueBoolean1WithoutArgCommand = ['e2e reg default-value-boolean1'];
const regDefaultValueBoolean1WithoutArgReturnsFalse = async (cli: Cli) => {
cli.run();
await waitForExpect(async () => {
const screen = cli.screen();
expect(screen).toEqual(expect.arrayContaining([expect.stringContaining('Hello false')]));
});
await expect(cli.exitCode()).resolves.toBe(0);
};
/**
* testDefaultValueBoolean1 - 2
*/
const annoDefaultValueBoolean2WithArgReturnsTrueDesc = 'default boolean1 with arg returns true (anno)';
const annoDefaultValueBoolean2WithArgCommand = ['e2e anno default-value-boolean1 --arg1'];
const annoDefaultValueBoolean2WithArgReturnsTrue = async (cli: Cli) => {
cli.run();
await waitForExpect(async () => {
const screen = cli.screen();
expect(screen).toEqual(expect.arrayContaining([expect.stringContaining('Hello true')]));
});
await expect(cli.exitCode()).resolves.toBe(0);
};
/**
* testDefaultValueBoolean1Registration - 2
*/
const regDefaultValueBoolean2WithArgReturnsTrueDesc = 'default boolean1 with arg returns true (reg)';
const regDefaultValueBoolean2WithArgCommand = ['e2e reg default-value-boolean1 --arg1'];
const regDefaultValueBoolean2WithArgReturnsTrue = async (cli: Cli) => {
cli.run();
await waitForExpect(async () => {
const screen = cli.screen();
expect(screen).toEqual(expect.arrayContaining([expect.stringContaining('Hello true')]));
});
await expect(cli.exitCode()).resolves.toBe(0);
};
/**
* testDefaultValueBoolean1 - 3
*/
const annoDefaultValueBoolean3WithArgReturnsFalseDesc = 'default boolean1 with arg returns false (anno)';
const annoDefaultValueBoolean3WithArgCommand = ['e2e anno default-value-boolean1 --arg1 false'];
const annoDefaultValueBoolean3WithArgReturnsFalse = async (cli: Cli) => {
cli.run();
await waitForExpect(async () => {
const screen = cli.screen();
expect(screen).toEqual(expect.arrayContaining([expect.stringContaining('Hello false')]));
});
await expect(cli.exitCode()).resolves.toBe(0);
};
/**
* testDefaultValueBoolean1Registration - 3
*/
const regDefaultValueBoolean3WithArgReturnsFalseDesc = 'default boolean1 with arg returns false (reg)';
const regDefaultValueBoolean3WithArgCommand = ['e2e reg default-value-boolean1 --arg1 false'];
const regDefaultValueBoolean3WithArgReturnsFalse = async (cli: Cli) => {
cli.run();
await waitForExpect(async () => {
const screen = cli.screen();
expect(screen).toEqual(expect.arrayContaining([expect.stringContaining('Hello false')]));
});
await expect(cli.exitCode()).resolves.toBe(0);
};
/**
* testDefaultValueBoolean2 - 1
*/
const annoDefaultValueBoolean2WithoutArgReturnsTrueDesc = 'default boolean2 without arg returns true (anno)';
const annoDefaultValueBoolean2WithoutArgCommand = ['e2e anno default-value-boolean2'];
const annoDefaultValueBoolean2WithoutArgReturnsTrue = async (cli: Cli) => {
cli.run();
await waitForExpect(async () => {
const screen = cli.screen();
expect(screen).toEqual(expect.arrayContaining([expect.stringContaining('Hello true')]));
});
await expect(cli.exitCode()).resolves.toBe(0);
};
/**
* testDefaultValueBoolean2Registration - 1
*/
const regDefaultValueBoolean2WithoutArgReturnsTrueDesc = 'default boolean2 without arg returns true (reg)';
const regDefaultValueBoolean2WithoutArgCommand = ['e2e reg default-value-boolean2'];
const regDefaultValueBoolean2WithoutArgReturnsTrue = async (cli: Cli) => {
cli.run();
await waitForExpect(async () => {
const screen = cli.screen();
expect(screen).toEqual(expect.arrayContaining([expect.stringContaining('Hello true')]));
});
await expect(cli.exitCode()).resolves.toBe(0);
};
/**
* testDefaultValueBoolean3 - 1
*/
const annoDefaultValueBoolean3WithoutArgReturnsFalseDesc = 'default boolean3 without arg returns false (anno)';
const annoDefaultValueBoolean3WithoutArgCommand = ['e2e anno default-value-boolean3'];
const annoDefaultValueBoolean3WithoutArgReturnsFalse = async (cli: Cli) => {
cli.run();
await waitForExpect(async () => {
const screen = cli.screen();
expect(screen).toEqual(expect.arrayContaining([expect.stringContaining('Hello false')]));
});
await expect(cli.exitCode()).resolves.toBe(0);
};
/**
* testDefaultValueBoolean3Registration - 1
*/
const regDefaultValueBoolean3WithoutArgReturnsFalseDesc = 'default boolean3 without arg returns false (reg)';
const regDefaultValueBoolean3WithoutArgCommand = ['e2e reg default-value-boolean3'];
const regDefaultValueBoolean3WithoutArgReturnsFalse = async (cli: Cli) => {
cli.run();
await waitForExpect(async () => {
const screen = cli.screen();
expect(screen).toEqual(expect.arrayContaining([expect.stringContaining('Hello false')]));
});
await expect(cli.exitCode()).resolves.toBe(0);
};
beforeEach(async () => {
waitForExpect.defaults.timeout = waitForExpectDefaultTimeout;
waitForExpect.defaults.interval = waitForExpectDefaultInterval;
@@ -139,6 +279,126 @@ describe('e2e commands default-value', () => {
},
testTimeout
);
it(
annoDefaultValueBoolean1WithoutArgReturnsFalseDesc,
async () => {
cli = new Cli({
command: command,
options: [...options, ...annoDefaultValueBoolean1WithoutArgCommand]
});
await annoDefaultValueBoolean1WithoutArgReturnsFalse(cli);
},
testTimeout
);
it(
regDefaultValueBoolean1WithoutArgReturnsFalseDesc,
async () => {
cli = new Cli({
command: command,
options: [...options, ...regDefaultValueBoolean1WithoutArgCommand]
});
await regDefaultValueBoolean1WithoutArgReturnsFalse(cli);
},
testTimeout
);
it(
annoDefaultValueBoolean2WithArgReturnsTrueDesc,
async () => {
cli = new Cli({
command: command,
options: [...options, ...annoDefaultValueBoolean2WithArgCommand]
});
await annoDefaultValueBoolean2WithArgReturnsTrue(cli);
},
testTimeout
);
it(
regDefaultValueBoolean2WithArgReturnsTrueDesc,
async () => {
cli = new Cli({
command: command,
options: [...options, ...regDefaultValueBoolean2WithArgCommand]
});
await regDefaultValueBoolean2WithArgReturnsTrue(cli);
},
testTimeout
);
it(
annoDefaultValueBoolean3WithArgReturnsFalseDesc,
async () => {
cli = new Cli({
command: command,
options: [...options, ...annoDefaultValueBoolean3WithArgCommand]
});
await annoDefaultValueBoolean3WithArgReturnsFalse(cli);
},
testTimeout
);
it(
regDefaultValueBoolean3WithArgReturnsFalseDesc,
async () => {
cli = new Cli({
command: command,
options: [...options, ...regDefaultValueBoolean3WithArgCommand]
});
await regDefaultValueBoolean3WithArgReturnsFalse(cli);
},
testTimeout
);
it(
annoDefaultValueBoolean2WithoutArgReturnsTrueDesc,
async () => {
cli = new Cli({
command: command,
options: [...options, ...annoDefaultValueBoolean2WithoutArgCommand]
});
await annoDefaultValueBoolean2WithoutArgReturnsTrue(cli);
},
testTimeout
);
it(
regDefaultValueBoolean2WithoutArgReturnsTrueDesc,
async () => {
cli = new Cli({
command: command,
options: [...options, ...regDefaultValueBoolean2WithoutArgCommand]
});
await regDefaultValueBoolean2WithoutArgReturnsTrue(cli);
},
testTimeout
);
it(
annoDefaultValueBoolean3WithoutArgReturnsFalseDesc,
async () => {
cli = new Cli({
command: command,
options: [...options, ...annoDefaultValueBoolean3WithoutArgCommand]
});
await annoDefaultValueBoolean3WithoutArgReturnsFalse(cli);
},
testTimeout
);
it(
regDefaultValueBoolean3WithoutArgReturnsFalseDesc,
async () => {
cli = new Cli({
command: command,
options: [...options, ...regDefaultValueBoolean3WithoutArgCommand]
});
await regDefaultValueBoolean3WithoutArgReturnsFalse(cli);
},
testTimeout
);
});
/**
@@ -197,5 +457,125 @@ describe('e2e commands default-value', () => {
},
testTimeout
);
it(
annoDefaultValueBoolean1WithoutArgReturnsFalseDesc,
async () => {
cli = new Cli({
command: command,
options: [...options, ...annoDefaultValueBoolean1WithoutArgCommand]
});
await annoDefaultValueBoolean1WithoutArgReturnsFalse(cli);
},
testTimeout
);
it(
regDefaultValueBoolean1WithoutArgReturnsFalseDesc,
async () => {
cli = new Cli({
command: command,
options: [...options, ...regDefaultValueBoolean1WithoutArgCommand]
});
await regDefaultValueBoolean1WithoutArgReturnsFalse(cli);
},
testTimeout
);
it(
annoDefaultValueBoolean2WithArgReturnsTrueDesc,
async () => {
cli = new Cli({
command: command,
options: [...options, ...annoDefaultValueBoolean2WithArgCommand]
});
await annoDefaultValueBoolean2WithArgReturnsTrue(cli);
},
testTimeout
);
it(
regDefaultValueBoolean2WithArgReturnsTrueDesc,
async () => {
cli = new Cli({
command: command,
options: [...options, ...regDefaultValueBoolean2WithArgCommand]
});
await regDefaultValueBoolean2WithArgReturnsTrue(cli);
},
testTimeout
);
it(
annoDefaultValueBoolean3WithArgReturnsFalseDesc,
async () => {
cli = new Cli({
command: command,
options: [...options, ...annoDefaultValueBoolean3WithArgCommand]
});
await annoDefaultValueBoolean3WithArgReturnsFalse(cli);
},
testTimeout
);
it(
regDefaultValueBoolean3WithArgReturnsFalseDesc,
async () => {
cli = new Cli({
command: command,
options: [...options, ...regDefaultValueBoolean3WithArgCommand]
});
await regDefaultValueBoolean3WithArgReturnsFalse(cli);
},
testTimeout
);
it(
annoDefaultValueBoolean2WithoutArgReturnsTrueDesc,
async () => {
cli = new Cli({
command: command,
options: [...options, ...annoDefaultValueBoolean2WithoutArgCommand]
});
await annoDefaultValueBoolean2WithoutArgReturnsTrue(cli);
},
testTimeout
);
it(
regDefaultValueBoolean2WithoutArgReturnsTrueDesc,
async () => {
cli = new Cli({
command: command,
options: [...options, ...regDefaultValueBoolean2WithoutArgCommand]
});
await regDefaultValueBoolean2WithoutArgReturnsTrue(cli);
},
testTimeout
);
it(
annoDefaultValueBoolean3WithoutArgReturnsFalseDesc,
async () => {
cli = new Cli({
command: command,
options: [...options, ...annoDefaultValueBoolean3WithoutArgCommand]
});
await annoDefaultValueBoolean3WithoutArgReturnsFalse(cli);
},
testTimeout
);
it(
regDefaultValueBoolean3WithoutArgReturnsFalseDesc,
async () => {
cli = new Cli({
command: command,
options: [...options, ...regDefaultValueBoolean3WithoutArgCommand]
});
await regDefaultValueBoolean3WithoutArgReturnsFalse(cli);
},
testTimeout
);
});
});

View File

@@ -53,4 +53,83 @@ public class DefaultValueCommands extends BaseE2ECommands {
.and()
.build();
}
@ShellMethod(key = LEGACY_ANNO + "default-value-boolean1", group = GROUP)
public String testDefaultValueBoolean1(
@ShellOption(defaultValue = "false") boolean arg1
) {
return "Hello " + arg1;
}
@Bean
public CommandRegistration testDefaultValueBoolean1Registration() {
return CommandRegistration.builder()
.command(REG, "default-value-boolean1")
.group(GROUP)
.withOption()
.longNames("arg1")
.defaultValue("false")
.type(boolean.class)
.and()
.withTarget()
.function(ctx -> {
boolean arg1 = ctx.getOptionValue("arg1");
return "Hello " + arg1;
})
.and()
.build();
}
@ShellMethod(key = LEGACY_ANNO + "default-value-boolean2", group = GROUP)
public String testDefaultValueBoolean2(
@ShellOption(defaultValue = "true") boolean arg1
) {
return "Hello " + arg1;
}
@Bean
public CommandRegistration testDefaultValueBoolean2Registration() {
return CommandRegistration.builder()
.command(REG, "default-value-boolean2")
.group(GROUP)
.withOption()
.longNames("arg1")
.defaultValue("true")
.type(boolean.class)
.and()
.withTarget()
.function(ctx -> {
boolean arg1 = ctx.getOptionValue("arg1");
return "Hello " + arg1;
})
.and()
.build();
}
@ShellMethod(key = LEGACY_ANNO + "default-value-boolean3", group = GROUP)
public String testDefaultValueBoolean3(
@ShellOption boolean arg1
) {
return "Hello " + arg1;
}
@Bean
public CommandRegistration testDefaultValueBoolean3Registration() {
return CommandRegistration.builder()
.command(REG, "default-value-boolean3")
.group(GROUP)
.withOption()
.longNames("arg1")
.required(false)
.type(boolean.class)
.defaultValue("false")
.and()
.withTarget()
.function(ctx -> {
boolean arg1 = ctx.getOptionValue("arg1");
return "Hello " + arg1;
})
.and()
.build();
}
}

View File

@@ -158,7 +158,13 @@ public class StandardMethodTargetRegistrar implements MethodTargetRegistrar, App
optionSpec.defaultValue(so.defaultValue());
}
if (ObjectUtils.nullSafeEquals(so.defaultValue(), ShellOption.NONE)) {
optionSpec.required();
if (ClassUtils.isAssignable(boolean.class, parameterType)) {
optionSpec.required(false);
optionSpec.defaultValue("false");
}
else {
optionSpec.required();
}
}
if (!ClassUtils.isAssignable(NoValueProvider.class, so.valueProvider())) {
CompletionResolver completionResolver = ctx -> {

View File

@@ -405,4 +405,42 @@ public class StandardMethodTargetRegistrarTests {
public void foo3(@ShellOption(defaultValue = ShellOption.NULL) String arg1) {
}
}
@Test
public void testOptionValuesWithBoolean() {
applicationContext = new AnnotationConfigApplicationContext(ValuesWithBoolean.class);
registrar.setApplicationContext(applicationContext);
registrar.register(catalog);
assertThat(catalog.getRegistrations().get("foo1")).isNotNull();
assertThat(catalog.getRegistrations().get("foo1").getOptions()).hasSize(1);
assertThat(catalog.getRegistrations().get("foo1").getOptions().get(0).getDefaultValue()).isEqualTo("false");
assertThat(catalog.getRegistrations().get("foo1").getOptions().get(0).isRequired()).isFalse();
assertThat(catalog.getRegistrations().get("foo2")).isNotNull();
assertThat(catalog.getRegistrations().get("foo2").getOptions()).hasSize(1);
assertThat(catalog.getRegistrations().get("foo2").getOptions().get(0).getDefaultValue()).isEqualTo("true");
assertThat(catalog.getRegistrations().get("foo2").getOptions().get(0).isRequired()).isFalse();
assertThat(catalog.getRegistrations().get("foo3")).isNotNull();
assertThat(catalog.getRegistrations().get("foo3").getOptions()).hasSize(1);
assertThat(catalog.getRegistrations().get("foo3").getOptions().get(0).isRequired()).isFalse();
assertThat(catalog.getRegistrations().get("foo3").getOptions().get(0).getDefaultValue()).isEqualTo("false");
}
@ShellComponent
public static class ValuesWithBoolean {
@ShellMethod(value = "foo1")
public void foo1(@ShellOption(defaultValue = "false") boolean arg1) {
}
@ShellMethod(value = "foo2")
public void foo2(@ShellOption(defaultValue = "true") boolean arg1) {
}
@ShellMethod(value = "foo3")
public void foo3(@ShellOption boolean arg1) {
}
}
}