I made an homebrew formula which is now accessible only on my local taps. I want to send pull request to homebrew-core. Now I am required to write test for my formula. How to write that based on example below?
test do
output = shell_output("#{bin}/balance 2>&1", 64)
assert_match "this is balance #{version}", output
end
My formula
#!/usr/bin/env ruby
def match
files = Dir.glob("*")
if ARGV.length == 0
puts "usage: match <keyword>"
return
end
files.each { |x|
if File.directory?(x)
puts "#{x}_ found directory"
puts "***"
next
end
found = false
File.open(x).each_line.with_index do |line, index|
if line.include? ARGV[0]
puts "#{x}_ #{index+1} #{line}"
found = true
end
end
puts "***" if found
}
end
match
Brew formula
class Match < Formula
desc "Browse all files inside any directory for a keyword"
homepage "https://github.com/aatalyk/homebrew-match"
url ""
sha256 ""
def install
bin.install "match"
end
end
Tests for shell commands in Homebrew formulae usually usually follow this scenario:
create a context usable by the command : a git repository, a directories hierarchy, a sample file, etc.
run the command
assert the result is correct
In your case since match is a grep -R -like you could create a bunch of files with some content, then run match <something> and ensure it finds the correct files.
You can use any Ruby code in your tests as well as Homebrew utilities such as shell_output("...command...") to get the output of a command.
Here is an example of test you could write:
class Match < Formula
# ...
test do
# Create two dummy files
(testpath/"file1").write "foo\nbar\nqux"
(testpath/"file2").write "bar\nabc"
# Ensure `match bar` finds both files
assert_match "file1_ 2 bar\n***\nfile2_ 1 bar",
shell_output("#{bin}/match bar")
# Ensure `match abc` finds the second file
assert_match "file2_ 2 abc", shell_output("#{bin}/match abc")
# Ensure `match idontmatchanything` doesn’t match any of the files
assert_not_match(/file[12]/,
shell_output("#{bin}/match idontmatchanything"))
end
end
assert_match "something", shell_output("command") ensures that (1) command runs successfully and (2) its output contains "something".
Related
How can you traverse directory to get to root in Python? I wrote some code using BeautifulSoup, but it says 'module not found'. So I have this:
#
# There is a directory traversal vulnerability in the
# following page http://127.0.0.1:8082/humantechconfig?file=human.conf
# Write a script which will attempt various levels of directory
# traversal to find the right amount that will give access
# to the root directory. Inside will be a human.conf with the flag.
#
# Note: The script can timeout if this occurs try narrowing
# down your search
import urllib.request
import os
req = urllib.request.urlopen("http://127.0.0.1:8082/humantechconfig?file=human.conf")
dirName = "/tmp"
def getListOfFiles(dirName):
listOfFile = os.listdir(dirName)
allFiles = list()
for entry in listOfFile:
# Create full path
fullPath = os.path.join(dirName, entry)
if os.path.isdir(fullPath):
allFiles = allFiles + getListOfFiles(fullPath)
else:
allFiles.append(fullPath)
return allFiles
listOfFiles = getListOfFiles(dirName)
print(listOfFiles)
for file in listOfFiles:
if file.endswith(".conf"):
f = open(file, "r")
print(f.read())
This outputs:
/tmp/level-0/level-1/level-2/human.conf
User : Human 66
Flag: Not-Set (Must be Root Human)
However. If I change the URL to 'http://127.0.0.1:8082/humantechconfig?file=../../../human.conf' it gives me the output:
User : Human 66
Flag: Not-Set (Must be Root Human)
User : Root Human
Flag: Well done the flag is: {}
The level of directory traversal it is at fluctuates wildly, from /tmp/level-2 to /tmp/level-15; if it's at the one I wrote, then it says I'm 'Root Human'. But it won't give me the flag, despite the fact that I am suddenly 'Root Human'. Is there something wrong with the way I am traversing directory?
It doesn't seem to matter at all if I take away the req = urllib.request.urlopen("http://127.0.0.1:8082/humantechconfig?file=human.conf") line. How can I actually send the code to that URL?
Thanks!
cyber discovery moon base challenge?
For this one, you need to keep adding '../' in front of human.conf (for example 'http://127.0.0.1:8082/humantechconfig?file=../human.conf') which becomes your URL. This URL you need to request (using urllib.request.urlopen(URL)).
The main bit of the challenge is to attach the ../ multiple times which shall not be very hard using a simple loop. You don't need to use the OS.
Make sure to break the loop once you find the flag (or it will go into an infinite loop and give you errors).
I wrote the below code, which will extract the directory name along with the file name and I will use purge command on that extracted Text.
$ sear VAXMANAGERS_ROOT:[PROC]TEMP.LIS LOG/out=VAXMANAGERS_ROOT:[DEV]FVLIM.TXT
$ OPEN IN VAXMANAGERS_ROOT:[DEV]FVLIM.TXT
$ LOOP:
$ READ/END_OF_FILE=ENDIT IN ABCD
$ GOTO LOOP
$ ENDIT:
$ close in
$ ERROR=F$EXTRACT(0,59,ABCD)
$ sh sym ERROR
$ purge/keep=1 'ERROR'
The output is as follows:
ERROR = "$1$DKC102:[PROD_LIVE.LOG]DP2017_TMP2.LIS;27392 "
Problem here is --- Every time the directory length varies (Length may be 59 or 40 or some other value, but the directory and filename length will not exceed 59 characters in my system). So in the above output, the system is also fetching the Version number of that file number. So I am not able to purge the file along with the version number.
%PURGE-E-PURGEVER, version numbers not permitted
Any suggestion -- How to eliminate the version number from the output ?
I cannot use the exact length of the directory, as directory length varies everytime.... :(
The answer with F$ELEMENT( 0, ";", ABCD ) should work, as confirmed. I might script something like this:
$ ERROR = F$PARSE(";",ERROR) ! will return $1$DKC102:[PROD_LIVE.LOG]DP2017_TMP2.LIS;
$ ERROR = ERROR - ";"
$ PURGE/KEEP=1 'ERROR'
Not sure why you have the read loop. What you will get is the last line in the file, but assuming that's what you want.
While HABO explained it, some more explanations
Suppose I use f$search to check if a file exists
a = f$search("sys$manager:net$server.log")
then I find I it exists
wr sys$output a
shows
SYS$SYSROOT:[SYSMGR]NET$SERVER.LOG;9
From the help of f$parse I get
help lex f$parse arg
shows, among other things
`Specifies a character string containing the name of a field
in a file specification. Specifying the field argument causes
the F$PARSE function to return a specific portion of a file
specification.
Specify one of the following field names (do not abbreviate):
NODE Node name
DEVICE Device name
DIRECTORY Directory name
NAME File name
TYPE File type
VERSION File version number`
So I can do
wr sys$output f$parse(a,,,"DEVICE")
which shows
SYS$SYSROOT:
and also
wr sys$output f$parse(a,,,"DIRECTORY")
so I get
[SYSMGR]
and
wr sys$output f$parse(a,,,"NAME")
shows
NET$SERVER
and
wr sys$output f$parse(a,,,"TYPE")
shows
.LOG
the version is
wr sys$output f$parse(a,,,"VERSION")
shown as
;9
The lexicals functions can be handy, check it using
help lexical
it shows
F$CONTEXT F$CSID F$CUNITS F$CVSI F$CVTIME F$CVUI F$DELTA_TIME F$DEVICE F$DIRECTORY F$EDIT
F$ELEMENT F$ENVIRONMENT F$EXTRACT F$FAO F$FID_TO_NAME F$FILE_ATTRIBUTES F$GETDVI F$GETENV
F$GETJPI F$GETQUI F$GETSYI F$IDENTIFIER F$INTEGER F$LENGTH F$LICENSE F$LOCATE F$MATCH_WILD
F$MESSAGE F$MODE F$MULTIPATH F$PARSE F$PID F$PRIVILEGE F$PROCESS F$READLINK F$SEARCH
F$SETPRV F$STRING F$SYMLINK_ATTRIBUTES F$TIME F$TRNLNM F$TYPE F$UNIQUE F$USER
It seems ncurses handles paste (from copy & paste) by inserting one character at a time from the text that was pasted, which can be slow if the handler for each character is slow.
I'd like to handle paste events myself, when a 'bracketed paste' sequence is detected, starting with ESC[200~ (see http://www.xfree86.org/current/ctlseqs.html#Bracketed%20Paste%20Mode).
How can I implement this in ncurses?
Here some code illustrating 'bracketed paste mode' (using Ruby curses).
There is only three key things:
0.) Make sure your terminal supports bracketed paste mode (such as for instance Windows 10 Terminal since about 1 month, see https://github.com/microsoft/terminal/releases/tag/v1.7.572.0)
1.) Switch on bracketed paste mode in the terminal by sending the ?2004h CSI.
print("\x1b[?2004h")
2.) When a paste occurs, recognize that you received \x1b[200~ to start parsing the pasted text and \x1b[201~ to recognize that the pasted text is finished.
# /usr/bin/ruby2.7
require "curses"
include Curses
def main_loop
init_screen
noecho # Disable Echoing of character presses
# Switch on braketed paste mode
print("\x1b[?2004h")
addstr("Please paste something into this terminal (make sure it supports braketed paste!) or press 'q' to quit.\n")
loop do
c = get_char2
case c
in 'q' # use q to quit
return
in csi: "200~" # Bracketed paste started
pasted = ""
loop do
d = get_char2
case d
in csi: "201~" # Bracketed paste ended
break
else
pasted += d
end
end
addstr("You pasted: #{pasted.inspect}\n")
else
addstr("You didn't paste something, you entered: #{c.inspect} #{c.class.name}\n")
end
end
ensure
close_screen
end
#
# For CSI, or "Control Sequence Introducer" commands,
# the ESC [ is followed by
# 1.) any number (including none) of "parameter bytes" in the range
# 0x30–0x3F (ASCII 0–9:;<=>?), then by
# 2.) any number of "intermediate bytes" in the range
# 0x20–0x2F (ASCII space and !"#$%&'()*+,-./), then finally by
# 3.) a single "final byte" in the range
# 0x40–0x7E (ASCII #A–Z[\]^_`a–z{|}~).
#
# From: https://handwiki.org/wiki/ANSI_escape_code
def get_csi
result = ""
loop do
c = get_char
result += c
if c.ord >= 0x40 && c.ord <= 0x7E
return result
end
end
end
# Just like get_char, but will read \x1b[<csi> and return it as a hash { csi: ... }, everything else is just returned as-is
def get_char2
c = get_char
case c
when "\e" # ESC
case get_char
when '['
return { csi: get_csi }
else
raise "¯\_(ツ)_/¯"
end
else
return c
end
end
main_loop()
I figured it works after enabling bracketed paste mode, but this needs to be done with raw terminal sequences since ncurses doesn't provide support for that by itself.
I have created a batch file that generates a file listing output to a text file and then displays that text file in a browser. Since the listing takes awhile to generate, I want a message box to display during processing (and ideally another message box to display at the end indicating that the process completed) before it displays to the browser.
Place a line at the beginning of your script and at the end of your script.
'echo "Entry"'
'echo "Exit"'
Have the output sent to a log file which updates. This will be different depending on your language, but fairly easy to do.
As a separate process make an if statement that greps for Enrty and Exit. In Bash it would be:
grep_output=`grep Entry <file>`
if [ "$grep_output" == "" ]; then
entryoutput=true;
else
entryoutput=false;
fi
grep_output=`grep Exit <file>`
if [ "$grep_output" == "" ]; then
exitoutput=true;
else
exitoutput=false;
fi
while :; do
if $entryoutput=true and exitoutput=false; then
sleep 10
done
Not 100% on the syntax of that two condition if statement above.
On TestUnit you can launch one test in file with -n option
for example
require 'test_helper'
class UserTest < ActiveSupport::TestCase
test "the truth" do
assert true
end
test "the truth 2" do
assert true
end
end
You can execute only the test the truth
ruby -Itest test/unit/user_test.rb -n test_the_truth
The ouput
1 tests, 1 assertions, 0 failures, 0 errors, 0 skip
How can that with rspec ?
The command seem not work
rspec spec/models/user_spec.rb -e "User the truth"
You didn't include the source of your spec, so it's hard to say where the problem is, but in general you can use the -e option to run a single example. Given this spec:
# spec/models/user_spec.rb
require 'spec_helper'
describe User do
it "is true" do
true.should be_true
end
describe "validation" do
it "is also true" do
true.should be_true
end
end
end
This command line:
rspec spec/models/user_spec.rb -e "User is true"
Will produce this output:
Run filtered including {:full_description=>/(?-mix:User\ is\ true)/}
.
Finished in 0.2088 seconds
1 example, 0 failures
And if you wanted to invoke the other example, the one nested inside the validation group, you'd use this:
rspec spec/models/user_spec.rb -e "User validation is also true"
Or to run all the examples in the validation group:
rspec spec/models/user_spec.rb -e "User validation"
You can also select in which line is the test case you want to execute.
rspec spec/models/user_spec.rb:8
By passing any line inside the scope of the test case, only this test case will be executed. You can also use this to execute a whole context inside your test.
At least in Rspec 2.11.1 you can use all of the following options:
** Filtering/tags **
In addition to the following options for selecting specific files, groups,
or examples, you can select a single example by appending the line number to
the filename:
rspec path/to/a_spec.rb:37
-P, --pattern PATTERN Load files matching pattern (default: "spec/**/*_spec.rb").
-e, --example STRING Run examples whose full nested names include STRING (may be
used more than once)
-l, --line_number LINE Specify line number of an example or group (may be
used more than once).
-t, --tag TAG[:VALUE] Run examples with the specified tag, or exclude examples
by adding ~ before the tag.
- e.g. ~slow
- TAG is always converted to a symbol