Skip to content

Commit

Permalink
Merge branch 'master' of ssh://github.com/ThrowTheSwitch/Ceedling
Browse files Browse the repository at this point in the history
  • Loading branch information
mvandervoord committed Jan 30, 2025
2 parents 9778164 + 58256dc commit fb1ce6c
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 47 deletions.
3 changes: 0 additions & 3 deletions assets/project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -269,9 +269,6 @@
# :html_encoding: UTF-8

# :module_generator:
# :path_src: source/
# :path_inc: includes/
# :path_tst: tests/
# :naming: :snake #options: :bumpy, :camel, :caps, or :snake
# :includes:
# :tst: []
Expand Down
4 changes: 0 additions & 4 deletions examples/temp_sensor/project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -221,10 +221,6 @@
# :html_encoding: UTF-8

# :module_generator:
# :project_root: ./
# :source_root: source/
# :inc_root: includes/
# :test_root: tests/
# :naming: :snake #options: :bumpy, :camel, :caps, or :snake
# :includes:
# :tst: []
Expand Down
20 changes: 17 additions & 3 deletions lib/ceedling/file_finder_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ def find_file_in_collection(filename, file_list, complain, original_filepath="")
return nil
end

def find_best_path_in_collection(pathname, path_list, complain)
def find_best_path_in_collection(pathname, path_list, complain, description)
# search our collection for the specified exact path
raise "No path list provided for search" if path_list.nil?
raise "No path list provided for #{description} search" if path_list.nil?
return pathname if path_list.include?(pathname)

# Determine the closest match by looking for matching path segments, especially paths ENDING the same
Expand All @@ -68,6 +68,20 @@ def find_best_path_in_collection(pathname, path_list, complain)
best_match_value = num
end
end

# If none of the options were a good match, handle to the best of our ability
if (best_match_value == 0) && (reverse_original_pieces.length > 0)
case (complain)
when :error
raise CeedlingException.new( "Found no path `#{pathname}` in #{description} search paths." )
when :warn
warning = "Found no path `#{pathname}` in #{description} search paths."
@loginator.log( warning, Verbosity::COMPLAIN )
when :ignore
# nothing further to do
end
end

return path_list[best_match_index]
end

Expand All @@ -94,7 +108,7 @@ def blow_up(filename, extra_message="")

def gripe(filename, extra_message="")
warning = ["Found no file `#{filename}` in search paths.", extra_message].join(' ').strip
@loginator.log( warning + extra_message, Verbosity::COMPLAIN )
@loginator.log( warning, Verbosity::COMPLAIN )
end

end
Expand Down
4 changes: 2 additions & 2 deletions lib/ceedling/file_path_collection_utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def collect_paths(paths)
# Expand paths using Ruby's Dir.glob()
# - A simple path will yield that path
# - A path glob will expand to one or more paths
# Note: `sort()` becuase of Github Issue #860
# Note: `sort()` because of Github Issue #860
@file_wrapper.directory_listing( _reformed ).sort.each do |entry|
# For each result, add it to the working list *only* if it's a directory
# Previous validation has already made warnings about filepaths in the list
Expand All @@ -57,7 +57,7 @@ def collect_paths(paths)
# (Containing parent directory still exists)
parents << FilePathUtils.no_decorators( _path ) if dirs.empty?

dirs += parents
dirs = parents + dirs
end

# Based on aggregation modifiers, add entries to plus and minus sets.
Expand Down
63 changes: 59 additions & 4 deletions plugins/module_generator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@ In this example, we'd create 9 files total: 3 headers, 3 source files, and 3 tes
files would be named `SecretLairModel`, `SecretLairConductor`, and `SecretLairHardware`. Isn't
that nice?

The module generator understands the following patterns:

- `src` -- generate only a source file
- `test` -- generate only a test file
- `dh` -- generate 6 files for the driver-hardware pattern
- `dih` -- generate 9 files for the driver-interrupt-hardware pattern
- `mch` -- generate 9 files for the model-conductor-hardware pattern
- `mvp` -- generate 9 files for the model-view-presenter pattern

### Paths

The directories found in the project `:paths:` are reused. You can also specify an alternative default generation path using:
Expand Down Expand Up @@ -97,13 +106,60 @@ You can see that more complicated structures will have files placed in the wrong
time... no worries... you can move the file after it's created... but if your project has any kind of
consistent structure, the guessing engine does a good job of making it work.

Three more quick notes about the path-matching:
A few more quick notes about the path-matching:

1. You can give multiple ordered hints that map roughly to folder nesting! `lab:secret:lair` will
happily match to put `lair.c` in a folder like `my/lab/secret/`.

2. Whenever the matcher fails to find a good candidate (or if it finds multiple equally good
candidates), it will always guess in the order you have the paths listed in your project.yml file
2. If the matcher isn't given any path information or it finds multiple equally good candidates,
it will always guess in the order you have the paths listed in your project.yml file

3. If the matcher completely fails to find a good candidate, it will return an error, allowing you
to rectify the situation.

4. What path is "first" when you're using `**` pattern in your `:paths:` specifications? The parent
folder is used first, then its children alphabetically, and so on. This is important when
considering where files (or especially subfolders... see below) will be generated.

### Adding to Paths

In addition to the pattern matching above, you can add slashes (`/`) to your filename specification.
When a slash is used instead of a colon (`:`), it will stop using pattern matching and assume the
subdirectory is supposed to be there. If the subdir is NOT there, it will automatically add it.

Let's try an example with our previous path specification:

```
:paths:
:source:
- src/** #this might contain subfolders lab, lair, and other
:include:
- inc/** #again, this might contain subfolders lab, lair, other, and shared
:test:
- test
```

Then, use the following command:

```
ceedling module:create[newlab/SecretLair]
```

This will create the following 3 files:

- `src/newlab/SecretLair.c`
- `inc/newlab/SecretLair.h`
- `test/newlab/TestSecretLair.c`

Technically, you can start with a colon and specify part of a path, then use a slash
to specify the remainder of the path to use. In most circumstances, this should work... however
it suffers from the same potential issues as the matcher above, with the added joy of creating
new subdirectories for you without asking.

It's important to note the module generator doesn't care if these new subdirectories are covered
by the current path specification. This allows you to create the files before updating the
`project.yml` file if desired, but it also means you might accidentally think you've created
a file that Ceedling can see, when it can't.

## Stubbing

Expand All @@ -130,7 +186,6 @@ follows the default ceedling structure... but what if you have a different struc

```
:module_generator:
:project_root: ./
:naming: :bumpy
:includes:
- :src: []
Expand Down
73 changes: 50 additions & 23 deletions plugins/module_generator/Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def prep_test
end

def prep_stub(num)
FileUtils.cp_r("../assets/stubby#{num}.h","./i/stubby.h")
FileUtils.cp_r("../assets/stubby#{num}.h","./i/rev/stubby.h")
end

def assert_file_exist(path)
Expand Down Expand Up @@ -81,6 +81,16 @@ def call_create(cmd)
end
end

def call_create_expecting_error(cmd)
retval = `#{CEEDLING_CLI_EXEC} module:create[#{cmd}] 2>&1`
puts retval # Debug logging
if retval.match? /Error/i
puts "Received expected error when creating #{cmd}"
else
raise "Should have received error when creating #{cmd}"
end
end

def call_destroy(cmd)
retval = `#{CEEDLING_CLI_EXEC} module:destroy[#{cmd}] 2>&1`
puts retval # Debug logging
Expand All @@ -101,6 +111,10 @@ def call_stub(cmd)
end
end

def puts_heading(title)
puts "\n\n#{title}\n#{"="*title.length}"
end

desc "Run integration test on example"
task :integration_test do
chdir("./example/") do
Expand All @@ -111,16 +125,16 @@ task :integration_test do

# Add a module without path.
# It should be added to first path on list of each category
puts "\nVerifying Default Create:"
puts_heading "Verifying Default Create:"
call_create("a_file")
assert_file_exist("s/rev/a_file.c")
assert_file_exist("i/rev/a_file.h")
assert_file_exist("s/a_file.c")
assert_file_exist("i/a_file.h")
assert_file_exist("sub/t/test_a_file.c")
assert_test_run_contains("TESTED: 1")

# Make sure that we can add modules properly when the directory
# pattern is subdirs with src, inc, and test folders each
puts "\nVerifying Subdirectory Create:"
puts_heading "Verifying Subdirectory Create:"
call_create("sub:b_file")
assert_file_exist("sub/s/b_file.c")
assert_file_exist("sub/i/b_file.h")
Expand All @@ -129,37 +143,37 @@ task :integration_test do

# Make sure that we can add modules properly when the directory
# pattern is subdirs under the src, inc, and test folders
puts "\nVerifying Reverse Subdirectory Create:"
puts_heading "Verifying Reverse Subdirectory Create:"
call_create("rev:c_file")
assert_file_exist("s/rev/c_file.c")
assert_file_exist("i/rev/c_file.h")
assert_file_exist("t/rev/test_c_file.c")
assert_test_run_contains("TESTED: 3")

# Does our Boilerplate mechanism work?
puts "\nVerifying Boilerplate:"
puts_heading "Verifying Boilerplate:"
assert_file_contains("s/rev/c_file.c", "MAY THE SOURCE BE WITH YOU")
assert_file_contains("i/rev/c_file.h", "feel included")
assert_file_contains("t/rev/test_c_file.c", "Don't Test Me, Sir")

# Are other essentials being injected
puts "\nVerifying Guts:"
assert_file_contains("s/rev/a_file.c", "#include \"a_file.h\"")
assert_file_contains("i/rev/a_file.h", "#ifndef A_FILE_H")
puts_heading "Verifying Guts:"
assert_file_contains("s/a_file.c", "#include \"a_file.h\"")
assert_file_contains("i/a_file.h", "#ifndef A_FILE_H")
assert_file_contains("sub/t/test_a_file.c", "test_a_file_NeedToImplement")

# Destroy a module without path.
# It should be removed from first path on list of each category
puts "\nVerifying Default Destroy:"
puts_heading "Verifying Default Destroy:"
call_destroy("a_file")
assert_file_not_exist("s/rev/a_file.c")
assert_file_not_exist("i/rev/a_file.h")
assert_file_not_exist("s/a_file.c")
assert_file_not_exist("i/a_file.h")
assert_file_not_exist("sub/t/test_a_file.c")
assert_test_run_contains("TESTED: 2")

# Make sure that we can destroy modules properly when the directory
# pattern is subdirs with src, inc, and test folders each
puts "\nVerifying Subdirectory Destroy:"
puts_heading "Verifying Subdirectory Destroy:"
call_destroy("sub:b_file")
assert_file_not_exist("sub/s/b_file.c")
assert_file_not_exist("sub/i/b_file.h")
Expand All @@ -168,36 +182,49 @@ task :integration_test do

# Make sure that we can destroy modules properly when the directory
# pattern is subdirs under the src, inc, and test folders
puts "\nVerifying Reverse Subdirectory Destroy:"
puts_heading "Verifying Reverse Subdirectory Destroy:"
call_destroy("rev:c_file")
assert_file_not_exist("s/rev/c_file.c")
assert_file_not_exist("i/rev/c_file.h")
assert_file_not_exist("t/rev/test_c_file.c")
assert_test_run_contains("No tests executed")

# Verify stubbing functionality can make a new source file
puts "\nVerifying Stubbing:"
puts_heading "Verifying Stubbing:"
prep_stub(1)
call_stub("i:stubby")
call_stub("rev:stubby")
assert_file_contains("s/rev/stubby.c","void shorty")

# Verify stubbing functionality can update a source file
puts "\nVerifying Stub Updating:"
puts_heading "Verifying Stub Updating:"
prep_stub(2)
call_stub("i:stubby")
call_stub("rev:stubby")
assert_file_contains("s/rev/stubby.c","void shorty")
assert_file_contains("s/rev/stubby.c","void shrimpy")
assert_file_contains("s/rev/stubby.c","int tiny")

# Make sure that we can destroy modules properly even when the
# entire set doesn't exist
puts "\nVerifying Partial Destroy:"
call_destroy("i:stubby")
puts_heading "Verifying Partial Destroy:"
call_destroy("rev:stubby")
assert_file_not_exist("s/rev/stubby.c")
assert_file_not_exist("i/rev/stubby.h")
prep_test

puts "\nPASSES MODULE SELF-TESTS"
# Make sure that it complains about path hints that don't match paths
puts_heading "Verifying Matcher Failure Handling:"
call_create_expecting_error("bad:stubby")
assert_file_not_exist("s/bad/stubby.c")
assert_file_not_exist("i/bad/stubby.h")

# Make sure it allows us to create a subdir if slash used
puts_heading "Verifying Default Create:"
call_create("slash/d_file")
assert_file_exist("s/slash/d_file.c")
assert_file_exist("i/slash/d_file.h")
assert_file_exist("sub/t/slash/test_d_file.c")

prep_test
puts_heading "PASSES MODULE SELF-TESTS"

end
end
Expand Down
1 change: 0 additions & 1 deletion plugins/module_generator/config/module_generator.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
# =========================================================================

:module_generator:
:project_root: ./
:naming: :snake #options: :bumpy, :camel, :caps, or :snake
:boilerplates:
:src: ""
Expand Down
3 changes: 1 addition & 2 deletions plugins/module_generator/example/project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -162,14 +162,13 @@
:release: []

:module_generator:
:project_root: ./
:naming: :snake #options: :bumpy, :camel, :caps, or :snake
:boilerplates:
:src: "/* MAY THE SOURCE BE WITH YOU */"
:inc: |
/* ==================================
| It's important to make everyone
| feel included, particularly in
| feel included, particularly
| when making important decisions.
===================================*/
:tst: "// Don't Test Me, Sir."
10 changes: 5 additions & 5 deletions plugins/module_generator/lib/module_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

class ModuleGenerator < Plugin

attr_reader :config
attr_reader :config, :interactionizer

def create(module_name, optz={})

Expand Down Expand Up @@ -110,10 +110,10 @@ def divine_options(optz={})
unity_generator_options[:path_tst] ||= unity_generator_options[:paths_tst][0]
else
# A path was specified. Do our best to determine which is the best choice based on this information
unity_generator_options[:skeleton_path] = @ceedling[:file_finder_helper].find_best_path_in_collection(optz[:module_root_path], unity_generator_options[:paths_src], :ignore) || unity_generator_options[:paths_src][0]
unity_generator_options[:path_src] = @ceedling[:file_finder_helper].find_best_path_in_collection(optz[:module_root_path], unity_generator_options[:paths_src], :ignore) || unity_generator_options[:paths_src][0]
unity_generator_options[:path_inc] = @ceedling[:file_finder_helper].find_best_path_in_collection(optz[:module_root_path], unity_generator_options[:paths_inc], :ignore) || unity_generator_options[:paths_inc][0]
unity_generator_options[:path_tst] = @ceedling[:file_finder_helper].find_best_path_in_collection(optz[:module_root_path], unity_generator_options[:paths_tst], :ignore) || unity_generator_options[:paths_tst][0]
unity_generator_options[:path_src] = @ceedling[:file_finder_helper].find_best_path_in_collection(optz[:module_root_path], unity_generator_options[:paths_src], :error, 'source') || unity_generator_options[:paths_src][0]
unity_generator_options[:path_inc] = @ceedling[:file_finder_helper].find_best_path_in_collection(optz[:module_root_path], unity_generator_options[:paths_inc], :error, 'include') || unity_generator_options[:paths_inc][0]
unity_generator_options[:path_tst] = @ceedling[:file_finder_helper].find_best_path_in_collection(optz[:module_root_path], unity_generator_options[:paths_tst], :error, 'test') || unity_generator_options[:paths_tst][0]
unity_generator_options[:skeleton_path] = unity_generator_options[:path_src]
end

return unity_generator_options
Expand Down

0 comments on commit fb1ce6c

Please sign in to comment.